problema de readarray (ou pipe)

19

Eu fiquei com um comportamento estranho de readarraycomando.

Os man bashestados:

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

mas esses scripts não funcionam (a matriz está vazia):

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

E estes funcionam:

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[@]}

O que há de errado com o cachimbo?

dchirikov
fonte

Respostas:

15

Talvez tente:

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

Espero que funcione, mas no momento em que você sair desse último contexto de {shell ; }no final do |pipeline, perderá seu valor variável. Isso ocorre porque cada um dos processos |separados |em um |pipeline é executado em um (subshell ). Portanto, sua coisa não funciona pelo mesmo motivo:

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

... não - o valor da variável foi definido em um processo shell diferente daquele em que você o chama.

mikeserv
fonte
23

Para garantir que o readarraycomando seja executado no shell atual, use a substituição de processo no lugar do pipeline:

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

ou (se bash4.2 ou posterior) use a lastpipeopção shell:

shopt -s lastpipe
( echo a; echo b; echo c ) | readarray arr
chepner
fonte
1
Legal. Isso funciona, mas o que exatamente é a substituição do processo? E o que significa ter < <2 flechas?
CMCDragonkai
1
Veja a bashpágina do manual. Em resumo, é uma sintaxe para tratar um pipeline como um descritor de arquivo. < <(...)significa redirecionar a entrada (a primeira <) da saída do comando dentro <(...). Similary, > >(...)passaria a saída padrão para a entrada padrão do pipeline dentro >(...). Você não precisa necessariamente usar o redirecionamento com a substituição do processo. cat <( echo a b c )funciona também.
Chepner
Ambas as opções produzem um resultado indesejável para mim, onde cada item da matriz retém as terminações de linha no final de cada sequência. Considerando que a resposta por smac89 não tem esse problema.
thnee
3

readarray também pode ler do stdin, então:

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