Tengo el siguiente archivo .txt:
Marco
Paolo
Antonio
Quiero leerlo línea por línea, y para cada línea quiero asignar un valor de línea .txt a una variable. Suponiendo que mi variable es$name
, el flujo es:
- Leer la primera línea del archivo
- Asignar
$name
= "Marco" - Haz algunas tareas con
$name
- Leer la segunda línea del archivo
- Asignar
$name
= "Paolo"
Respuestas:
Lo siguiente lee un archivo pasado como argumento línea por línea:
Esta es la forma estándar para leer líneas de un archivo en un bucle. Explicación:
IFS=
(oIFS=''
) evita que se recorten los espacios en blanco iniciales / finales.-r
evita que se interpreten los escapes de barra invertida.O puede ponerlo en un script de ayuda de archivo bash, contenido de ejemplo:
Si lo anterior se guarda en un script con nombre de archivo
readfile
, se puede ejecutar de la siguiente manera:Si el archivo no es un archivo de texto POSIX estándar (= no terminado por un carácter de nueva línea), el bucle puede modificarse para manejar líneas parciales finales:
Aquí,
|| [[ -n $line ]]
evita que se ignore la última línea si no termina con un\n
(ya queread
devuelve un código de salida distinto de cero cuando encuentra EOF).Si los comandos dentro del bucle también se leen desde la entrada estándar, el descriptor de archivo utilizado por se
read
puede cambiar a otra cosa (evite los descriptores de archivo estándar ), por ejemplo:(Los shells que no son Bash pueden no saberlo
read -u3
; en suread <&3
lugar, úselos)fuente
ssh
sin la-n
bandera efectivamente hará que escapes del bucle. Probablemente haya una buena razón para esto, pero me tomó un tiempo descubrir qué estaba causando que mi código fallara antes de descubrir esto.ffmpeg
consumo de stdin. Agregue</dev/null
a suffmpeg
línea y no podrá o usará un FD alternativo para el bucle. Ese enfoque de "FD alternativo" se parecewhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
extensión. Los ejecutables en UNIX no suelen tener extensiones (no se ejecutals.elf
), y tener un bash shebang (y herramientas solo para bash como[[ ]]
) y una extensión que implica la compatibilidad POSIX sh es internamente contradictorio.Te animo a que uses la
-r
banderaread
que significa:Estoy citando de
man 1 read
.Otra cosa es tomar un nombre de archivo como argumento.
Aquí está el código actualizado:
fuente
sh
, nobash
; El comando de prueba extendido utilizado en la|| [[ -n "$line" ]]
sintaxis en la respuesta aceptada es un bashism. Dicho esto, esa sintaxis en realidad tiene un significado pertinente: hace que el bucle continúe para la última línea en el archivo de entrada, incluso si no tiene una nueva línea. Si quisieras hacer eso de una manera compatible con POSIX, te gustaría|| [ -n "$line" ]
usarlo en[
lugar de hacerlo[[
.IFS=
para elread
para evitar el recorte de los espacios en blanco.El uso de la siguiente plantilla de Bash debería permitirle leer un valor a la vez de un archivo y procesarlo.
fuente
*
.fuente
Enter
después de la última línea); de lo contrario, se ignorará la última línea. Al menos eso es lo que me pasó.Muchas personas han publicado una solución que está demasiado optimizada. No creo que sea incorrecto, pero humildemente creo que sería deseable una solución menos optimizada para permitir que todos entiendan fácilmente cómo está funcionando esto. Aquí está mi propuesta:
fuente
Utilizar:
Si ha configurado de manera
IFS
diferente, obtendrá resultados extraños.fuente
*
en una línea? De todos modos, este es un antipatrón . No lea líneas con for .read
enfoque es el enfoque de mejores prácticas por consenso de la comunidad . La advertencia que menciona en su comentario es una que se aplica cuando su ciclo ejecuta comandos (comoffmpeg
) que leen desde stdin, resueltos trivialmente utilizando un FD que no sea stdin para el ciclo o redirigiendo la entrada de dichos comandos. Por el contrario, evitar el error global en sufor
enfoque de bucle significa hacer (y luego tener que revertir) los cambios de configuración global de shell.for
enfoque de bucle que usa aquí significa que todo el contenido debe leerse antes de que el bucle pueda comenzar a ejecutarse, lo que lo hace completamente inutilizable si está pasando por gigabytes de datos, incluso si ha deshabilitado pegajoso elwhile read
bucle no necesita almacenar más de una sola línea de datos a la vez, lo que significa que puede comenzar a ejecutarse mientras el subproceso genera contenido todavía en ejecución (por lo tanto, puede utilizarse para fines de transmisión), y también ha limitado el consumo de memoria.while
enfoques basados en pares parecen tener problemas con los caracteres *. Vea los comentarios de la respuesta aceptada arriba. Sin embargo, no estoy discutiendo en contra de la iteración por archivos que son un antipatrón.Si necesita procesar tanto el archivo de entrada como la entrada del usuario (o cualquier otra cosa de stdin), use la siguiente solución:
Basado en la respuesta aceptada y en el tutorial de redirección de bash-hackers .
Aquí, abrimos el descriptor de archivo 3 para el archivo pasado como argumento de script y le pedimos
read
que use este descriptor como input (-u 3
). Por lo tanto, dejamos el descriptor de entrada predeterminado (0) adjunto a un terminal u otra fuente de entrada, capaz de leer la entrada del usuario.fuente
Para el manejo adecuado de errores:
fuente
Lo siguiente solo imprimirá el contenido del archivo:
fuente
Use la herramienta IFS (separador de campo interno) en bash, define el carácter que usa para separar las líneas en tokens, por defecto incluye < tab > / < space > / < newLine >
Paso 1 : Cargue los datos del archivo e insértelos en la lista:
Paso 2 : ahora itera e imprime la salida:
echo índice específico en la matriz : Acceso a una variable en la matriz:
fuente