Supponiamo di avere questo file:
$ 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
Esistono quattro elementi che alterano il significato dell'output del file letto da molte soluzioni Bash:
- La riga vuota 4;
- Spazi iniziali o finali su due linee;
- Mantenere il significato delle singole linee (cioè ogni linea è un record);
- La riga 6 non è terminata con un CR.
Se si desidera il file di testo riga per riga, comprese le righe vuote e le righe di fine senza CR, è necessario utilizzare un ciclo while e disporre di un test alternativo per la riga finale.
Ecco i metodi che possono modificare il file (rispetto a ciò che cat
restituisce):
1) Perdere l'ultima riga e gli spazi iniziali e finali:
$ 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'
(Se lo fai while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
invece, conservi gli spazi iniziali e finali ma perdi comunque l'ultima riga se non termina con CR)
2) Usando la sostituzione del processo con cat
will si legge l'intero file in un sorso e si perde il significato delle singole righe:
$ 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'
(Se rimuovi "
da $(cat /tmp/test.txt)
te leggi il file parola per parola piuttosto che un sorso. Probabilmente non è quello che intendi ...)
Il modo più robusto e semplice per leggere un file riga per riga e preservare tutta la spaziatura è:
$ 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'
Se desideri rimuovere gli spazi iniziali e commerciali, rimuovi la IFS=
parte:
$ 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'
(Un file di testo senza terminazione \n
, sebbene abbastanza comune, è considerato rotto in POSIX. Se puoi contare sul trascinamento \n
non è necessario || [[ -n $line ]]
nelwhile
loop.)
Maggiori informazioni sulle FAQ di BASH