Un script toma una URL, la analiza en busca de los campos obligatorios y redirige su salida para guardarla en un archivo, file.txt . La salida se guarda en una nueva línea cada vez que se encuentra un campo.
file.txt
A Cat
A Dog
A Mouse
etc...
Quiero tomar file.txt
y crear una matriz a partir de ella en un nuevo script, donde cada línea llega a ser su propia variable de cadena en la matriz. Hasta ahora lo he intentado:
#!/bin/bash
filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)
for (( i = 0 ; i < 9 ; i++))
do
echo "Element [$i]: ${myArray[$i]}"
done
Cuando ejecuto este script, los espacios en blanco dan como resultado que las palabras se dividan y en lugar de obtener
Salida deseada
Element [0]: A Cat
Element [1]: A Dog
etc...
Termino recibiendo esto:
Salida real
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
¿Cómo puedo ajustar el bucle a continuación de modo que toda la cadena en cada línea corresponda uno a uno con cada variable en la matriz?
Respuestas:
Usa el
mapfile
comando:mapfile -t myArray < file.txt
El error está usando
for
: la forma idiomática de recorrer las líneas de un archivo es:while IFS= read -r line; do echo ">>$line<<"; done < file.txt
Consulte BashFAQ / 005 para obtener más detalles.
fuente
while IFS= read -r; do lines+=("$REPLY"); done <file
.mapfile
no se ejecutará como se espera en muchas máquinas sin pasos adicionales. @ericslaw Mac continuará distribuyéndose con bash 3.2.57 en el futuro previsible. Las versiones más recientes usan una licencia que requeriría que Apple compartiera o permitiera cosas que no quieren compartir o permitir.mapfile
yreadarray
(que son sinónimos) están disponibles en Bash versión 4 y superior. Si tiene una versión anterior de Bash, puede usar un bucle para leer el archivo en una matriz:arr=() while IFS= read -r line; do arr+=("$line") done < file
En caso de que el archivo tenga una última línea incompleta (falta una línea nueva), puede usar esta alternativa:
arr=() while IFS= read -r line || [[ "$line" ]]; do arr+=("$line") done < file
Relacionado:
fuente
IFS= read -r line || [[ "$line" ]]
para que funcione. De lo contrario, ¡funciona muy bien!do
?Tu también puedes hacer esto:
oldIFS="$IFS" IFS=$'\n' arr=($(<file)) IFS="$oldIFS" echo "${arr[1]}" # It will print `A Dog`.
Nota:
La expansión del nombre de archivo todavía se produce. Por ejemplo, si hay una línea con un literal
*
, se expandirá a todos los archivos de la carpeta actual. Por lo tanto, utilícelo solo si su archivo está libre de este tipo de escenario.fuente
IFS
solo temporalmente (para que recupere su valor original después de este comando), mientras persiste la asignaciónarr
?IFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
IFS=... command
no cambiaIFS
en el shell actual. Sin embargo,IFS=... other_variable=...
(sin ningún comando) cambia ambosIFS
yother_variable
en el shell actual.arr=
notación (en comparación conmapfile
/readarray
).Simplemente puede leer cada línea del archivo y asignarla a una matriz.
#!/bin/bash i=0 while read line do arr[$i]="$line" i=$((i+1)) done < file.txt
fuente
Utilice mapfile o read -a
Siempre verifique su código usando shellcheck . A menudo le dará la respuesta correcta. En este caso, SC2207 cubre la lectura de un archivo que tiene valores separados por espacios o por líneas nuevas en una matriz.
No hagas esto
Archivos con valores separados por líneas nuevas
mapfile -t array < <(mycommand)
Archivos con valores separados por espacios
IFS=" " read -r -a array <<< "$(mycommand)"
La página de shellcheck le dará la razón por la que esto se considera la mejor práctica.
fuente
Esta respuesta dice usar
mapfile -t myArray < file.txt
Hice una corrección para
mapfile
si quieres usarlamapfile
en bash <4.x por cualquier motivo. Utiliza elmapfile
comando existente si está en bash> = 4.xActualmente, solo opciones
-d
y-t
trabajo. Pero eso debería ser suficiente para el comando anterior. Solo lo he probado en macOS. En macOS Sierra 10.12.6, el bash del sistema es3.2.57(1)-release
. Así que la calza puede resultar útil. También puede actualizar su bash con homebrew, construir bash usted mismo, etc.Utiliza esta técnica para configurar variables en una pila de llamadas.
fuente