Załóżmy, że masz ten plik:
$ 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
Istnieją cztery elementy, które zmienią znaczenie danych wyjściowych pliku odczytanych przez wiele rozwiązań Bash:
- Pusta linia 4;
- Przednie lub końcowe spacje na dwóch liniach;
- Utrzymanie znaczenia poszczególnych linii (tj. Każda linia jest zapisem);
- Linia 6 nie jest zakończona CR.
Jeśli chcesz, aby plik tekstowy linia po linii obejmował puste linie i linie końcowe bez CR, musisz użyć pętli while i mieć alternatywny test dla ostatniej linii.
Oto metody, które mogą zmienić plik (w porównaniu do tego, co cat
zwraca):
1) Strać ostatnią linię oraz spacje wiodące i końcowe:
$ 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'
(Jeśli to zrobisz while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
, zachowujesz początkowe i końcowe spacje, ale nadal tracisz ostatni wiersz, jeśli nie jest on zakończony CR)
2) Użycie substytucji procesu cat
spowoduje odczytanie całego pliku w jednym łyku i utratę znaczenia poszczególnych wierszy:
$ 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'
(Jeśli usuniesz "
z $(cat /tmp/test.txt)
, przeczytasz plik słowo po słowie zamiast jednego łyka. Prawdopodobnie też nie to, co jest zamierzone ...)
Najbardziej niezawodny i najprostszy sposób na odczytanie pliku wiersz po wierszu i zachowanie wszystkich odstępów:
$ 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'
Jeśli chcesz usunąć przestrzenie wiodące i handlowe, usuń IFS=
część:
$ 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'
(Plik tekstowy bez zakończenia \n
, choć dość powszechny, jest uważany za uszkodzony w POSIX. Jeśli możesz liczyć na końcowe \n
, nie potrzebujesz || [[ -n $line ]]
w while
pętli.)
Więcej na stronie BASH FAQ