Supongamos que tiene este archivo:
$ 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
Hay cuatro elementos que alterarán el significado de la salida del archivo leída por muchas soluciones de Bash:
- La línea en blanco 4;
- Espacios iniciales o finales en dos líneas;
- Mantener el significado de líneas individuales (es decir, cada línea es un registro);
- La línea 6 no terminó con un CR.
Si desea que el archivo de texto línea por línea incluya líneas en blanco y líneas de terminación sin CR, debe usar un bucle while y debe tener una prueba alternativa para la línea final.
Estos son los métodos que pueden cambiar el archivo (en comparación con lo que cat
devuelve):
1) Pierda la última línea y los espacios iniciales y finales:
$ 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'
(Si lo hace while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
, conserva los espacios iniciales y finales pero aún pierde la última línea si no termina con CR)
2) El uso de la sustitución de procesos con cat
will lee todo el archivo de una vez y pierde el significado de las líneas individuales:
$ 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'
(Si se quita la "
de $(cat /tmp/test.txt)
leer el archivo de la palabra por palabra en lugar de un solo trago. También probablemente no lo que se pretende ...)
La forma más sólida y sencilla de leer un archivo línea por línea y preservar todo el espaciado es:
$ 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'
Si desea eliminar los espacios iniciales y comerciales, elimine 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 archivo de texto sin una terminación \n
, aunque bastante común, se considera roto bajo POSIX. Si puede contar con el seguimiento \n
no necesita || [[ -n $line ]]
en el while
bucle).
Más en las preguntas frecuentes de BASH