script loop for ejemplos define create array arrays bash loops scripting variable-assignment

arrays - loop - linux shell define array



Crear una matriz a partir de un archivo de texto en Bash (6)

Use mapfile o lea -a

Siempre revise 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 espacio o por línea nueva en una matriz.

No hagas esto

array=( $(mycommand) )

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 cual esto se considera la mejor práctica.

Un script toma una URL, la analiza para 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 él en un nuevo script, donde cada línea se convierta en su propia variable de cadena en la matriz. Hasta ahora 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, el espacio en blanco hace que las palabras se dividan y en lugar de obtener

Salida deseada

Element [0]: A Cat Element [1]: A Dog etc...

Termino obteniendo 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?


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


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 ocurre. Por ejemplo, si hay una línea con un literal * , se expandirá a todos los archivos en la carpeta actual. Úselo solo si su archivo está libre de este tipo de escenario.


Use el comando mapfile :

mapfile -t myArray < file.txt

El error se usa 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

Ver BashFAQ/005 para más detalles.


Esta respuesta dice usar

mapfile -t myArray < file.txt

Hice una shim para mapfile si desea usar mapfile en bash <4.x por cualquier razón. Utiliza el comando mapfile existente si está en bash> = 4.x

Actualmente, solo funcionan las opciones -d y -t . Pero eso debería ser suficiente para ese comando anterior. Solo lo he probado en macOS. En macOS Sierra 10.12.6, el bash del sistema es 3.2.57(1)-release . Entonces la cuña puede ser ú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.


mapfile y readarray (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 nueva línea), puede usar esta alternativa:

arr=() while IFS= read -r line || [[ "$line" ]] do arr+=("$line") done < file

Relacionado: