HOWTO · Linux
Cómo leer un archivo línea por línea usando Bash
Usamos el comando de lectura en Bash para leer un archivo línea por línea.
En esta página
Bash puede procesar un archivo de texto línea por línea con el comando read dentro de un bucle while. Así, la entrada se procesa como un flujo y el script no necesita guardar todo el archivo en memoria. Usa IFS= para conservar los espacios en blanco iniciales y finales, -r para preservar las barras invertidas y pon "$line" entre comillas cada vez que expandas el valor.
Leer un archivo línea por línea con un bucle while
Un bucle fiable lee el archivo mediante una redirección de entrada. La condición || [[ -n $line ]] también permite procesar la última línea si el archivo no termina con un salto de línea. El bucle procesa el archivo como un flujo y mantiene el total acumulado en el shell actual.
El ejemplo completo de abajo crea su propia entrada numérica, muestra cada valor y suma los seis números: 1, 5, 6, 7, 8 y 10. El total es 37. Las etiquetas y los mensajes que aparecen en la salida permanecen en inglés: identifican cada valor mostrado y anuncian la suma total.
#!/usr/bin/env bash
set -u
file=$(mktemp)
trap 'rm -f "$file"' EXIT
printf '%s\n' 1 5 6 7 8 10 > "$file"
sum=0
printf 'The numbers in the file are:\n'
while IFS= read -r line || [[ -n $line ]]; do
printf '%s\n' "$line"
sum=$((sum + line))
done < "$file"
printf 'The sum of the numbers in the file is:%s\n' "$sum"
The numbers in the file are:
1
5
6
7
8
10
The sum of the numbers in the file is:37
La redirección de entrada mantiene el bucle en el shell actual, por lo que los cambios, como el total acumulado, siguen disponibles después del bucle. Evita expandir una variable sin comillas, por ejemplo, $line: la separación de palabras y la expansión de nombres de ruta pueden alterar su contenido.
Dividir cada línea en campos
Para separar registros por un delimitador, primero lee cada línea sin procesar y después asigna sus campos. En una lectura delimitada, la última variable de read recibe los campos restantes. Este ejemplo crea y procesa los cinco registros: Rohit-10, Harish-30, Manish-50, Kapil-10 y Anish-20. La condición para la última línea también procesa un último registro no vacío cuando el archivo no termina con un salto de línea.
#!/usr/bin/env bash
set -u
file=$(mktemp)
trap 'rm -f "$file"' EXIT
printf '%s\n' 'Rohit-10' 'Harish-30' 'Manish-50' 'Kapil-10' 'Anish-20' > "$file"
while IFS= read -r line || [[ -n $line ]]; do
IFS=- read -r name earnings <<< "$line"
printf '%s has made earnings of %s pounds today!\n' "$name" "$earnings"
done < "$file"
Rohit has made earnings of 10 pounds today!
Harish has made earnings of 30 pounds today!
Manish has made earnings of 50 pounds today!
Kapil has made earnings of 10 pounds today!
Anish has made earnings of 20 pounds today!
En este caso, IFS=- establece el guion como delimitador de la lectura que asigna los campos. Con dos variables, name recibe el texto anterior al primer guion y earnings recibe el resto. Al imprimir, pon las variables entre comillas para que su contenido se pase como valores individuales.
Elegir otro método para leer archivos en Bash
Usa el patrón while IFS= read -r line cuando quieras procesar cada línea a medida que llega o cuando el archivo pueda ser mayor que la memoria disponible. Para un archivo normal, redirígelo directamente al bucle; ejecutar cat mediante sustitución de procesos no aporta nada en ese caso. La sustitución de procesos puede ser útil si el bucle debe leer la salida generada por un comando en vez de un archivo.
Si tu instalación de Bash incluye mapfile, puedes cargar las líneas del archivo en una matriz, por ejemplo, con mapfile -t lines < "$file". Elige esta opción si los pasos posteriores necesitan acceder a las líneas por índice o recorrerlas varias veces, y el archivo completo cabe en memoria. La opción -t elimina el salto de línea final de cada línea. La disponibilidad depende de la instalación de Bash; si necesitas un método más ampliamente aplicable, usa el bucle que procesa el archivo como un flujo.