problema de readarray (ou pipe)

Fiquei com um comportamento estranho do comando readarray.

O man bash afirma:

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 isso funciona:

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 tubo?

Resposta

Talvez tente:

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

Espero que funcione , mas no momento em que você sai do último { shell ; } contexto no final do | pipeline lá você perderá o valor da 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 “t – o valor da variável foi definido em um diferente / em> processo shell do que aquele em que você o chama.

Resposta

Para garantir o readarray comando é executado no shell atual, use a substituição do processo no lugar do pipeline:

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

ou (if bash 4.2 ou posterior) use a opção de shell lastpipe:

shopt -s lastpipe ( echo a; echo b; echo c ) | readarray -t arr 

Comentários

  • Legal. Isso funciona, mas o que exatamente é substituição de processo? E o que significa ter < < 2 setas?
  • Consulte a página do manual bash. Em suma, é a sintaxe ' para tratar um pipeline como um descritor de arquivo. < <(...) significa redirecionar a entrada (o primeiro <) da saída do comando dentro de <(...). Da mesma forma, > >(...) passaria a saída padrão para a entrada padrão do pipeline dentro de >(...). Você não ' não precisa necessariamente usar o redirecionamento com substituição de processo. cat <( echo a b c ) também funciona.
  • Ambas as opções produzem um resultado indesejável para mim, onde cada item do array retém as terminações de linha no final de cada string. Considerando que a resposta por smac89 não tem esse problema.
  • Os finais de linha podem ser removidos usando readarray -t arr. De man bash: -t Remove a trailing newline from each line read.
  • Eu ' estou usando bash 5.0.17 e isso não ' não funciona para mim. Eu ' verifiquei BASHOPTS e contém lastpipe, mas cat myfile.txt | readarray -t arr fornece um arr vazio, mas readarray -t arr < <(cat myfile.txt) funciona corretamente.

Resposta

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

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

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *