Por que a tubulação e o redirecionamento funcionam de maneira diferente com os documentos aqui?

4

Combinar um redirecionamento com um documento aqui parece bastante lógico:

$ bash > foo <<EOF
echo Hello
EOF

$ less foo
Hello

Mas com um pipe, ele se comporta de maneira diferente:

$ bash | tee foo <<EOF
echo Hello
EOF

$ less foo
echo Hello

O que também é estranho é se você digitar imediatamente 'history':

$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...

Ou seja, o primeiro comando ainda parece estar dentro do bash recém-criado. O que está acontecendo? Por que o tubo se comporta de maneira diferente?

    
por Steve Bennett 24.02.2014 / 11:35

1 resposta

7

Você está redirecionando a entrada de tee , não bash . Use:

bash << EOF | tee foo
echo Hello
EOF

Mais alguns exemplos para ilustrar como funciona:

bash << EO1 3<< EO | tee 3<< EO3 foo 4<< EO4
fed (as a deleted temp file open in read-only mode) to bash fd 0
EO1
fed to bash fd 3 without $variable and $(cmd) expansion
EO2
fed to tee fd 3
(not that tee does anything with its fd 3)
EO3
fed to tee fd 4
(see how, like any redirection operator 3<< END can appear anywhere on
the command line (for simple commands at least))
EO4

Redirecionando comandos compostos:

{ head -n2; wc -l; } << EOF
fed as fd 0 for the whole command group
$(ps -e)
EOF

Ou:

if head -n1; then
  head -n2
fi << EOF
1
2
3
EOF

Você pode reutilizar o mesmo token de finalização:

$ ls -l /proc/self/fd << E 3<< E >&2 | 3<< E 4<< E ls -l /proc/self/fd
pipe heredoc> E
pipe heredoc> E
pipe heredoc> E
pipe heredoc> E
total 0
lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> /tmp/zshLiVzp3 (deleted)
lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5
lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5
lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshFLbQ7T (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /proc/25749/fd/
total 0
lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> pipe:[70735808]
lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5
lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5
lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshL3KBp3 (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /tmp/zshcJjS7T (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 5 -> /proc/25748/fd/

Por que o primeiro comando history é executado nesse novo bash in:

$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...

Isso porque bash stdin ainda é o terminal, mas seu stdout é um canal morto (na outra extremidade do canal, tee redirecionou seu stdin desse arquivo temporário de exclusão, portanto, o final de leitura desse tubo está fechado).

bash não escreve seu prompt ou o eco do que você digita em seu stdout (o canal morto), mas no terminal, de modo que bash permitirá que você digite history no primeiro prompt.

No entanto, esse history (que é um embutido, assim executado pelo processo bash , não um filho), gravará sua saída para esse canal morto. Ao fazer isso, o processo bash receberá um sinal SIGPIPE (já que não há leitor) e morrerá.

O próximo prompt será emitido pelo shell de chamada.

    
por 24.02.2014 / 11:41