É possível redirecionar a saída de um comando para mais de um comando?

21

Até onde sei, posso usar o comando tee para dividir a saída padrão na tela e mais arquivos:

command -option1 -option2 argument | tee file1 file2 file3 

É possível redirecionar a saída para comandos em vez de arquivos usando tee, para que eu pudesse, teoricamente, criar uma cadeia de comandos?

    
por Abdul Al Hazred 08.03.2015 / 22:25

4 respostas

25

Você pode usar pipes nomeados ( link ) na linha de comando de tee e ter os comandos lendo nos pipes nomeados.

mkfifo /tmp/data0 /tmp/data1 /tmp/data2
cmd0 < /tmp/data0 & cmd1 < /tmp/data1 & cmd2 < /tmp/data2 &
command -option1 -option2 argument | tee /tmp/data0 /tmp/data1 /tmp/data2

Quando command terminar, tee fechará os pipes nomeados, o que sinalizará um EOF (lido de 0 bytes) em cada um dos /tmp/dataN que normalmente terminaria os processos cmdN . Exemplo real:

$ mkfifo /tmp/data0 /tmp/data1 /tmp/data2
$ wc -l < /tmp/data0 & wc -w < /tmp/data1 & wc -c < /tmp/data2 &
$ tee /tmp/data0 /tmp/data1 /tmp/data2 < /etc/passwd >/dev/null
$ 61
1974
37

Devido aos processos em segundo plano, o shell retornou um prompt antes da saída do programa. Todas as três instâncias de wc terminaram normalmente.

    
por 08.03.2015 / 22:46
15

Se eu entendi corretamente, você está procurando o equivalente a tee file1 file2 file3 , mas em vez de gravar os mesmos dados em três arquivos file1 , file2 e file3 , você deseja enviar os mesmos dados três comandos cmd1 , cmd2 e cmd3 , ou seja

… | ??? cmd1 cmd2 cmd3

deve ser equivalente a

… | cmd1 &
… | cmd2 &
… | cmd3 &

exceto que seria executado apenas uma vez.

Existem duas maneiras de fazer isso.

Ksh93, bash e zsh suportam substituição de processos . Essa é uma generalização de pipes que permite que o argumento de um comando seja um arquivo que, quando gravado, passa dados como entrada para um comando (também existe a variante de entrada que, quando lida, obtém a saída de dados por um comando) . Isto é,

echo hello | tee >(cmd1)

imprime hello para a saída padrão e, além disso, executa cmd1 com hello como entrada.

Por exemplo, se você quiser duplicar a entrada de somecommand e passá-la para ambos os grupos cmd1 e cmd2 , você pode usar

somecommand | tee >(cmd1) | cmd2

Se o seu shell não suportar a substituição do processo, você poderá usar pipes nomeados. Veja a resposta do Arcege para saber como isso funciona. Os pipes nomeados são menos convenientes do que a substituição do processo porque você precisa criá-los e excluí-los, além de iniciar e sincronizar os processos manualmente. Eles têm a vantagem de serem totalmente portáteis, enquanto nem todos os shells suportam substituições de processos. Eles também podem ser usados em cenários diferentes daqueles para os quais a substituição do processo serve.

Sob o capô, em alguns sistemas, a substituição de processos usa pipes nomeados internamente. Na maioria dos sistemas, porém, ele se baseia em arquivos nomeados representando os descritores de arquivos .

    
por 08.03.2015 / 23:22
6

Pelo menos em , você pode ignorar mkfifo usando a substituição do processo :

command -option1 -option2 argument | tee >(cmd1) >(cmd2) >(cmd3)

ou para adotar o exemplo do Arcege

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null
    
por 09.03.2015 / 13:26
3

Estou surpreso que ninguém mencionou o comando pee de moreutils ( link ).

    
por 10.03.2015 / 22:19