Предположим, у вас есть этот файл:
$ cat /tmp/test.txt
Line 1
Line 2 has leading space
Line 3 followed by blank line
Line 5 (follows a blank line) and has trailing space
Line 6 has no ending CR
Существует четыре элемента, которые изменят значение вывода файла, читаемого многими решениями Bash:
- Пустая строка 4;
- начальные или конечные пробелы в двух строках;
- Сохранение значения отдельных строк (т. Е. Каждая строка является записью);
- Строка 6 не заканчивается символом CR.
Если вы хотите, чтобы текстовый файл построчно включал пустые строки и завершающие строки без CR, вы должны использовать цикл while и иметь альтернативный тест для последней строки.
Вот методы, которые могут изменить файл (по сравнению с тем, что возвращает cat
):
1) Потерять последнюю строку, пробелы в начале и в конце:
$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
(Если вы вместо этого сделаете while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
, вы сохраните начальные и конечные пробелы, но по-прежнему потеряете последнюю строку, если она не заканчивается на CR)
2) Использование подстановки процесса с помощью cat
считывает весь файл за один раз и теряет значение отдельных строк:
$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
Line 2 has leading space
Line 3 followed by blank line
Line 5 (follows a blank line) and has trailing space
Line 6 has no ending CR'
(Если вы удалите "
из $(cat /tmp/test.txt)
, вы прочитаете файл слово за словом, а не одним глотком. Также, вероятно, не то, что предполагается ...)
Самый надежный и простой способ построчно читать файл и сохранять все пробелы:
$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
' Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space '
'Line 6 has no ending CR'
Если вы хотите убрать ведущие и торговые пробелы, удалите часть IFS=
:
$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'
(Текстовый файл без завершающего \n
, хотя и довольно распространенный, считается поврежденным в POSIX. Если вы можете рассчитывать на конечный \n
, вам не нужно || [[ -n $line ]]
в цикле while
.)
Больше на BASH FAQ