Posso especificar uma entrada redirecionada antes de um comando composto?

7

Bash permite que você especifique uma entrada redirecionada antes de um comando:

$ <lines sed 's/^/line: /g'
line: foo
line: bar

O Bash também permite redirecionar a entrada para um comando composto, como um loop while :

$ while read line; do echo "line: $line"; done <lines
line: foo
line: bar

No entanto, quando tento especificar uma entrada redirecionada antes de um loop while , recebo um erro de sintaxe:

$ <lines while read line; do echo "line: $line"; done
bash: syntax error near unexpected token 'do'

O que há de errado com isso? Não é possível especificar uma entrada redirecionada antes de um comando composto no Bash? Se sim, porque não?

    
por Stuart P. Bentley 17.09.2014 / 16:03

4 respostas

9

man bash diz:

... redirection operators may precede or appear anywhere within a simple command or may follow a command.

while não é um comando simples.

    
por 17.09.2014 / 16:10
5

Você pode, em zsh , não em bash e coroba, já indicar a documentação , mas se você quiser redirecionar antes, pode fazer coisas como:

< file eval '
  while IFS= read -r line; do
    ...
  done'

Ou (em sistemas com suporte para /dev/fd/n ):

< file 3<< 'EOF' . /dev/fd/3
while IFS= read -r line; do
  ...
done
EOF

(não que você queira fazer isso).

Você também pode fazer:

exec 3< file
while IFS= read -r line <&3; do
  ...
done
exec 3<&-

(observe que exec sairá do script se file não puder ser aberto).

Ou use uma função:

process()
  while IFS= read -r line; do
    ...
  done

< file process
    
por 17.09.2014 / 16:57
3

Você pode usar essa substituição se quiser preceder a entrada:

cat lines | while read line; do echo "line: $line"; done
    
por 17.09.2014 / 16:20
2

Você pode usar exec para redirecionar o stdin.

Em um script:

exec < <(cat lines)
while read line ; do echo "line: $line"; done

Você não pode usar em um shell de login (ele irá despejar o arquivo no stdout e sair). Nesse caso, você pode abrir um descritor de arquivo diferente:

exec 3< <(cat lines)
while read -u 3 line ; do echo "line: $line"; done

Para referência: Usando o exec

    
por 17.09.2014 / 19:55