Usando “while read…” em um script linux

28

Alguém poderia explicar como o código a seguir funciona?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

Especificamente, gostaria de saber por que a saída desse loop é 3 4 5 6 2 1 , em vez de 3 2 1 e 6 5 4 em duas linhas separadas? Eu não consigo me envolver com isso ...

    
por linuxgringo 02.04.2015 / 23:11

2 respostas

36

read lê uma linha inteira da entrada padrão, divide a linha em campos e atribui esses campos às variáveis dadas. Se houver mais partes que variáveis, as peças restantes serão atribuídas à última variável.

No seu caso $a é atribuído 1 , $b é atribuído 2 e $c o restante 3 4 5 6 .

    
por Florian Diesch 02.04.2015 / 23:27
23

Reescrevendo o loop dessa maneira revela o que está acontecendo:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Isso fornece, como saída:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Observe primeiro que apenas um único comando echo é executado. Se ele fosse executado mais de uma vez, você veria, entre outras coisas, as substrings (iteration beginning) e (iteration ending) impressas mais de uma vez.

Isso significa que ter um loop while aqui não está realmente realizando nada. O read builtin lê o texto separado por espaço em branco 1 em cada variável especificada. A entrada extra é anexada ao final da última variável especificada. 2 Assim, as variáveis a e b assumem os valores 1 e 2 respectivamente, enquanto c assume o valor 3 4 5 6 .

Quando a condição de loop ( while read a b c ) é avaliada pela segunda vez, não há mais entrada disponível do pipe (nós apenas canalizamos uma única linha de texto), então o comando read é avaliado como falso em vez de true e o loop pára (antes de executar o corpo uma segunda vez).

1 : Para ser técnico e específico, o read builtin , quando passou nomes de variáveis como argumentos, lê a entrada, dividindo-o em "palavras" separadas quando encontrar espaços em branco IFS (ver também esta questão e este artigo ).

2 : O comportamento de read de bloquear qualquer campo extra de entrada na última variável especificada não é intuitivo para muitos criadores de scripts, no início. Torna-se mais fácil entender quando você considera que como a resposta de Florian Diesch diz , read será sempre (tente) uma linha inteira - e que read se destina a ser utilizável com e sem loop.

    
por Eliah Kagan 02.04.2015 / 23:31

Tags