problema de readarray (o tubería)

19

Me quedé con un extraño comportamiento de readarraymando.

Los man bashestados:

readarray
     Read lines from the standard input into the indexed array variable array

pero estos scripts no funcionan (la matriz está vacía):

unset arr; (echo a; echo b; echo c) | readarray arr; echo ${#arr[@]}
unset arr; cat /etc/passwd | readarray arr;  echo ${#arr[@]}

Y estos funcionan:

unset arr; readarray arr < /etc/passwd ;  echo ${#arr[@]}
unset arr; mkfifo /tmp/fifo; (echo a; echo b; echo c) > /tmp/fifo & mapfile arr < /tmp/fifo ; echo ${#arr[@]}

¿Qué hay de malo con la tubería?

dchirikov
fuente

Respuestas:

15

Quizás intente:

unset arr
printf %s\\n a b c | {
    readarray arr
    echo ${#arr[@]}
}

Espero que funcione, pero en el momento en que salgas del último contexto de {shell ; }al final de la |tubería, perderás tu valor variable. Esto se debe a que cada uno de los procesos |separados |dentro de una |tubería se ejecuta en una (subshell ). Entonces tu cosa no funciona por la misma razón:

( arr=( a b c ) ) ; echo ${arr[@]}

... no lo hace: el valor de la variable se configuró en un proceso de shell diferente al que usted llama.

mikeserv
fuente
23

Para garantizar que el readarraycomando se ejecute en el shell actual, utilice la sustitución del proceso en lugar de la tubería:

readarray arr < <( echo a; echo b; echo c )

o (si es bash4.2 o posterior) use la lastpipeopción de shell:

shopt -s lastpipe
( echo a; echo b; echo c ) | readarray arr
chepner
fuente
1
Frio. Esto funciona, pero ¿qué es exactamente la sustitución del proceso? ¿Y qué significa tener < <2 flechas?
CMCDragonkai
1
Ver la bashpágina del manual. En resumen, es una sintaxis para tratar una tubería como un descriptor de archivo. < <(...)significa redirigir la entrada (la primera <) desde la salida del comando dentro <(...). De manera similar, > >(...)pasaría la salida estándar a la entrada estándar de la tubería en el interior >(...). No necesariamente necesita usar la redirección con la sustitución del proceso. cat <( echo a b c )funciona igual de bien
chepner 01 de
Ambas opciones producen un resultado no deseado para mí, donde cada elemento de la matriz retiene las terminaciones de línea al final de cada cadena. Mientras que la respuesta de smac89 no tiene este problema.
Thnee 01 de
3

readarray también puede leer desde stdin, entonces:

readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
smac89
fuente