En más de una ocasión he tenido que tratar algún archivo linea a linea en un script bash y siempre utilizó alguna de estos tres métodos:

  1. Usando los comandos head, tail y wc con tuberías
  2. Modificando la variable $IFS
  3. Redireccionando un bucle While

Usando los comandos head, tail y wc con tuberías

El comando head nos muestra por defecto las 10 primeras lineas de un archivo pero podemos modificar este comportamiento mediante un argumento que le indicará a head la cantidad de lineas que queremos que muestre de la siguiente manera:

 head -5 soyunarchivo 

En el ejemplo anterior se nos mostrarán las 5 primeras lineas del archivo soyunarchivo.

El comando tail muestra por defecto las 10 ultimas lineas de un archivo y al igual que head se puede modificar para que muestre las n últimas lineas:

 tail -2 soyunarchivo 

En el ejemplo se nos mostrarán las dos últimas lineas del archivo soyunarchivo.

Con estos dos comandos y una tubería que se encargue de pasar la salida de head a tail podemos ver una sola linea. Un ejemplo:

head -12 soyunarchivo | tail -1

En la linea anterior head muestra las 12 primeras lineas y tail nos muestra la última linea de esas 12 de forma que la linea que veremos será la número 12. Si queremos ver la línea 4 basta con modificar el -12 por -4 y se nos mostrará la línea 4.

Ahora si metemos esta instrucción en un bucle de tipo for podremos mostrar el archivo desde la primera linea hasta la última.

#!/bin/bash
TOTAL=`cat soyarchivo | wc -l`
for A in `seq 1 $TOTAL` ; do
  head -$A soyarchivo | tail -1
done

El comando cat muestra el contenido del archivo y pasando la salida a través de una tubería hacia wc con el argumento -l nos devuelve el número de líneas que tiene un archivo. El resultado se almacena en una variable que sirve para finalizar el bucle for.

Modificando la variable IFS

#!/bin/bash
OLDIFS=$IFS
IFS=$'\n'
for A in $(cat soyarchivo) ; do
  echo $A
done
IFS=$OLDIFS

La variable IFS (Internal Field Separator) es una variable de entorno que sirve para indicar al intérprete bash cómo debe reconocer los campos en una cadena de caracteres. Por defecto el separador es el espacio en blanco (tabuladores y saltos de linea incluidos).

En el código de arriba primero se almacena el valor original de IFS en una variable temporal, después se modifica para que el carácter separador sea únicamente el salto de linea, de esta forma en la variable A del bucle for se irán guardando todos los caracteres que haya entre cada salto de línea o hasta que se termine el archivo.

Redireccionando un bucle While

while read A ; do
  echo $A
done < soyunarchivo

En este último script hacemos que la entrada que tomará el comando read sea cada linea del archivo soyunarchivo y saldrá del bucle while cuando se llegue al final del archivo.

Resumiendo

Cualquiera de estas tres formas de leer un archivo linea a linea es completamente válida y dependiendo del script que estemos programando será más conveniente usar una forma u otra.