¿Cómo puedo leer el contenido de un fichero línea a línea con Bash?

publicado por: Anonymous

Tengo un fichero con este contenido:

Hola qué tal
Yo t muy bien
    Un placer.

Quiero leerlo línea a línea, guardando el valor de cada línea en una variable para procesarlo.

Es decir, quiero:

  • Leer la primera línea.
  • Realizar la asignación del valor "Hola qué tal" a la variable $linea.
  • Hacer cosas con $linea.
  • Leer la segunda línea.
  • Asignar el valor "Yo t muy bien" a $linea.

Y así sucesivamente.

solución

Utiliza while ... do ... done < fichero con algún matiz:

while IFS='' read -r linea || [[ -n "$linea" ]]; do
    printf ">%s<n" "$linea"
done < fichero

Lo que se explica como:

  • IFS='' (o IFS=) impide que se eliminen los caracteres de espacio (espacio o tabulador) iniciales o finales.
  • -r impide que la contrabarra () se interprete como un carácter especial.
  • || [[ -n $linea ]] impide que se ignore la última línea si no termina con n (pues read devuelve un exit no-cero cuando encuentra un EOF). Teóricamente, una línea debe terminar con n y así lo define POSIX: Secuencia de cero o más caracteres distintos de una nueva línea n seguido de un carácter de nueva línea. Sin embargo, puede darse el caso que se haya escrito un fichero en el que la última línea no lo contenga; con esta adición, también se procesaría dicha línea.

Así, en tu fichero tendríamos esta salida:

$ while IFS= read -r linea || [[ -n "$linea" ]]; do printf ">%s<n" "$linea"; done < fichero
>Hola qué tal<
>Yo t muy bien<
>   Un placer.<

Veamos qué pasaría si elimináramos alguna de las comprobaciones:

Sin IFS='': se eliminan los espacios iniciales y finales.

$ while read -r linea || [[ -n "$linea" ]]; do printf ">%s<n" "$linea"; done < a
>Hola qué tal<
>Yo t muy bien<
>Un placer.<      # ¡esto tenía espacios al principio!

Sin -r en read: se interpreta la contrabarra.

$ while IFS= read linea || [[ -n "$linea" ]]; do printf ">%s<n" "$linea"; done < a
>Hola qué tal<
>Yo t muy bien<   # ¡aquí había un t!
>   Un placer.<

Sin || [[ -n $linea ]]: una hipotética última línea no terminada en n no se leería:

Dado el fichero anterior, si le añadimos una nueva serie de caracteres sin n final:

$ printf "ueee" >> fichero

Observamos que su contenido aparece de esta forma:

$ cat -vet fichero
Hola quM-CM-) tal$
Yo t muy bien$
   Un placer.$
ueee              # se superpone al prompt

Cuando leemos, esta última línea no se procesa:

$ while IFS= read -r linea; do printf ">%s<n" "$linea"; done < fichero
>Hola qué tal<
>Yo t muy bien<
>   Un placer.<   # la línae ueee" no se lee

Referencias:

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *