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

21

Tanto quanto sei, posso usar o comando tee para dividir a saída padrão na tela e em outros 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?

Abdul Al Hazred
fonte
3
Explique o que você quer dizer com "sinal de saída" e descreva o que você quer dizer com criação de uma "rede de comandos".
Janis
no linux, cada comando possui uma entrada e duas saídas. eles são rotulados com 0 (para entrada), 1 (para saída) e 2 (para saída de erro). Eu estava pensando em 1 quando disse "sinal de saída" porque li que o comando tee divide apenas a saída rotulada 1. Quando eu disse "rede de comandos" eu não era muito técnico, não tenho certeza de como a rede está definida corretamente. um ponto de vista matemático, mas eu estava simplesmente pensando em uma árvore de comandos tipologicamente falando, para que alguns comandos possam ser pais de mais de um comando filho.
Abdul Al Hazred
Obrigado pelo seu esclarecimento. Por favor, não use a palavra sinal, pois ela tem um significado específico no Unix, e o termo era muito enganador neste contexto. Obrigado novamente.
Janis
Na linha de comando, digite man -k signal para aprender o significado especial desse conceito-chave no UNIX e Linux. man kill seria uma boa página para começar.
Rob
Além disso, muitas pessoas se referem ao stdin stdout e stderr como 'fluxos' de entrada ou saída. Existem pequenos rios de dados, portanto, um riacho. Você estava certo ao tentar uma palavra para descrevê-los coletivamente, mas sinal é apenas a palavra errada.
Rob

Respostas:

25

Você pode usar pipes nomeados ( http://linux.die.net/man/1/mkfifo ) na linha de comando teee 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 commandterminar, teefechará os pipes nomeados, que sinalizarão um EOF (leitura de 0 bytes) em cada um dos /tmp/dataNquais normalmente encerraria os cmdNprocessos. 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

Por causa dos processos em segundo plano, o shell retornou um prompt antes da saída do programa. Todas as três instâncias wcterminaram normalmente.

Arcege
fonte
1
No bash , você pode proteger muitas digitações via /tmp/data/{0,1,2}. Então, novamente, em bash, você poderia usar a substituição de processo e ignorar mkfifointeiramente
Tobias KIENZLER
2
Pode querer alterar / dev / data0 para / tmp / data0. Além disso, obrigado por responder à pergunta de uma maneira independente de shell. Isso é mais útil do que assumir que todos estão usando o bash.
abonet 13/03/2015
15

Se bem entendi, você está procurando o equivalente a tee file1 file2 file3, mas ao invés de escrever os mesmos dados para três arquivos file1, file2e file3, que pretende canalizar os mesmos dados em três comandos cmd1, cmd2e cmd3, isto é,

… | ??? cmd1 cmd2 cmd3

deve ser equivalente a

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

exceto que isso seria executado apenas uma vez.

Existem duas maneiras de fazer isso.

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

echo hello | tee >(cmd1)

gravuras hellopara a saída padrão e em adição é executada cmd1com hellocomo entrada.

Por exemplo, se você deseja duplicar a entrada somecommande passá-la para ambos cmd1e cmd2, 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 da Arcege para saber como isso funciona. Os pipes nomeados são menos convenientes do que a substituição do processo, porque você deve criá-los e excluí-los, além de iniciar e sincronizar 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 de processo é.

Sob o capô, em alguns sistemas, a substituição de processos usa pipes nomeados internamente. Na maioria dos sistemas, no entanto, ele se baseia em arquivos nomeados que representam descritores de arquivos .

Gilles 'SO- parar de ser mau'
fonte
5
Veja também peede moreutils.
Stéphane Chazelas
Observe que a substituição do processo foi introduzida pelo ksh88.
Stéphane Chazelas
6

Pelo menos no você pode pular mkfifousando a substituição de processo:

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

ou adotar o exemplo de Arcege

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null
Tobias Kienzler
fonte