Aprende leyendo en orden

Leer la entrada — procesar línea por línea con while read

Este artículo forma parte del Curso de Linux, con el que dominarás desde cero habilidades prácticas de Linux, desde los comandos básicos hasta los scripts de shell.
Con while read name age divides data.txt línea por línea en columnas y la formateas, con for f in "$@" procesas en orden los varios archivos pasados como argumentos, y pasas la entrada a read con pipes o here-doc — ilustrado y practicado en una terminal.

Leer un archivo línea por línea — while read

A menudo quieres procesar listas o archivos de configuración línea por línea.

Si escribes while read line; do … done < file, se lee file de arriba abajo una línea cada vez, se mete esa línea en la variable line y se repite el cuerpo de do … done.

No importa cuántas líneas tenga el archivo, el bucle continúa automáticamente hasta la última línea.

read divide la línea recibida por los espacios y puede repartirla en varias variables.

Si escribes while read name age; do …, la primera palabra de cada línea entra en name y la siguiente en age.

Con datos donde se alinean «nombre valor», como una lista, puedes extraer cada columna y darle formato.

printf 'web running\ndb stopped\n' > services.txt   # crear un archivo de ejemplo
while read svc state; do                              # leer línea a línea en svc y state
  echo "Servicio $svc esta $state"
done < services.txt                                   # services.txt como entrada
# salida: Servicio web esta running / Servicio db esta stopped
Procesar un archivo línea por línea con while read
data.txtwhile read name agename = aliceage = 30línea a línea1.ª palabra2.ª palabrarepetir hasta agotar las líneas
while read name age lee el archivo línea por línea y, separando por espacios, mete la primera palabra en name y la siguiente en age.
SintaxisSignificadoEjemplo
while read v; do … done < fProcesar el archivo f línea por línea con la variable vwhile read l; do echo "$l"; done < data.txt
while read a b; do …Dividir una línea por espacios en varias variableswhile read name age; do echo "$name"; done < data.txt

Vas a crear un script que lee un archivo de lista línea por línea con while read y lo formatea con la forma «nombre tiene edad años».

① Crea con printf 'alice 30\nbob 25\ncarol 41\n' > data.txt un archivo de ejemplo donde se alinea «nombre edad».

② Abre roster.sh con vi roster.sh, entra en modo de inserción con i y escribe un script que lea línea por línea con while read name age y que con echo imprima «$name tiene $age años» (con #!/bin/sh en la primera línea). Cuando lo tengas, guarda con Esc:wq.

③ Añade permiso de ejecución con chmod +x roster.sh, ejecuta ./roster.sh y comprueba que salen las 3 líneas ya formateadas.

④ Si no estás seguro de qué escribir, puedes copiar el cuerpo del panel de respuesta y pegarlo en el modo de inserción de vi.

(Ejecútalo correctamente y aparecerá la explicación).

Linux console
0 / 4 completado(s)
Loading Linux Terminal...

Recibir varios archivos por argumentos — "$@" y $(cat f)

Si fijas dentro del script el nombre del archivo a procesar, no podrás usarlo con otro archivo.

Si lo pasas al ejecutar, como ./show.sh a.txt b.txt, $1 es el primer argumento y $2 el segundo.

Todos los argumentos los recibes juntos con "$@".

Si escribes for f in "$@"; do … done, puedes meter los archivos pasados uno a uno en f y procesarlos en orden.

Cuando quieras usar el archivo entero junto como una cadena, lo cargas en una variable con text=$(cat "$f").

El número de argumentos lo sabes con $#, y si es 0 puedes hacer que muestre el modo de uso.

printf 'line A1\nline A2\n' > a.txt              # archivo de ejemplo 1
printf 'line B1\n' > b.txt                       # archivo de ejemplo 2
vi show.sh   # abrir en el editor, escribir lo siguiente y guardar con :wq
#   #!/bin/sh
#   for f in "$@"; do
#     echo "--- $f ---"
#     cat "$f"
#   done
chmod +x show.sh
./show.sh a.txt b.txt                            # mostrar los 2 archivos en orden con encabezado
Procesar en orden los varios archivos pasados como argumentos
./view.sh a.txt b.txt$1 = a.txt$2 = b.txtfor f in "$@" procesa en orden1.º2.º"$@" recibe todo y procesa en orden
Los archivos del momento de ejecución entran en $1 $2, y con "$@" los recibes juntos y los procesas uno a uno con for.
SintaxisSignificadoEjemplo
for f in "$@"; do …Procesar en orden cada archivo de los argumentosfor f in "$@"; do cat "$f"; done
$(cat f)Cargar el archivo entero en una sola cadenatext=$(cat data.txt)
$#Número de argumentos (si es 0, mostrar el uso)[ "$#" -eq 0 ] && echo usage

Vas a crear un script que procesa uno a uno por argumentos los nombres de archivo recibidos y muestra en orden el encabezado y el contenido.

① Crea dos archivos de ejemplo con printf 'apple\nbanana\n' > fruit.txt y printf 'red\nblue\n' > color.txt.

② Abre view.sh con vi view.sh, entra en modo de inserción con i y escribe un script que reciba los argumentos uno a uno con for f in "$@", imprima un encabezado con echo y luego cargue el archivo entero en una variable y muestre su contenido (con #!/bin/sh en la primera línea). Cuando lo tengas, guarda con Esc:wq.

③ Añade permiso de ejecución con chmod +x view.sh, ejecuta ./view.sh fruit.txt color.txt y comprueba que los 2 archivos se muestran en orden.

④ Si no estás seguro de qué escribir, puedes copiar el cuerpo del panel de respuesta y pegarlo en el modo de inserción de vi.

Linux console
0 / 5 completado(s)
Loading Linux Terminal...

Entrada interactiva y por pipe — read y here-doc

read no solo lee archivos, también lee la entrada que teclea una persona o la que se pasa por un pipe.

Hay formas como encadenar con un pipe al estilo echo hi | read v, o pasar de golpe la entrada del momento con un here-doc <<'EOF' … EOF.

Es la base para combinar tu script con otros comandos.

# leer línea por línea la salida de un pipe
printf 'one\ntwo\n' | while read v; do echo "linea: $v"; done
# pasar la entrada del momento con un here-doc
while read v; do echo "valor: $v"; done <<'EOF'
x
y
EOF
# entrada manual una sola vez (teclea name y pulsa Enter)
# al ejecutar queda a la espera de entrada
read name; echo "Hola $name"
Pasar la entrada a read sin archivo
printf 'cat\ndog'| while read vprocesar línea a línea<<'EOF' … EOFwhile read vprocesar línea a líneapasar por pipepasar con here-doc
Aunque no haya archivo, puedes pasar la entrada a while read línea por línea con un pipe o un here-doc.
SintaxisSignificadoEjemplo
cmd | while read v; do …Procesar línea por línea la salida de un pipecat data.txt | while read l; do echo "$l"; done
<<'EOF' … EOFPasar la entrada del momento con un here-docwhile read l; do echo "$l"; done <<'EOF'

Vas a crear un script que pasa la entrada a while read con un pipe y un here-doc, sin pasar por un archivo.

① Abre pipe.sh con vi pipe.sh, entra en modo de inserción con i y escribe un script que pase por pipe la salida de printf 'cat\ndog\n' a while read v; do echo "Animal: $v"; done (con #!/bin/sh en la primera línea). Cuando lo tengas, guarda con Esc:wq.

② Añade permiso de ejecución con chmod +x pipe.sh, ejecuta ./pipe.sh y comprueba que salen 2 líneas.

③ Comprueba que la salida es Animal: cat y Animal: dog, y que pudiste procesar la entrada línea por línea sin crear ningún archivo.

④ Si no estás seguro de qué escribir, puedes copiar el cuerpo del panel de respuesta y pegarlo en el modo de inserción de vi.

Linux console
0 / 3 completado(s)
Loading Linux Terminal...
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Cómo procesa file la construcción while read line; do … done < file?

Pregunta 2¿Qué notación representa juntos todos los argumentos pasados al script?

Pregunta 3¿Cómo procesas con read línea por línea la salida de un comando sin crear un archivo?