Existe uma maneira de canalizar a saída de um programa para outros dois programas?

28

Desculpe se esta é uma pergunta boba, mas estou tentando realizar algo assim, mas em uma linha:

$ prog1 | prog2
$ prog1 | prog3

Então, basicamente quero executar prog1 e canalizar a saída para prog2 e prog3 separadamente (não um pipe encadeado). No começo, eu estava tentando usar o tee, mas isso não parecia certo porque estava transferindo a saída para um arquivo (o que não é o que eu quero).

$ prog1 | tee prog2 | prog3 # doesn't work - creates file "prog2"

Em algum momento, eu provavelmente gostaria de estender isso para canalizar a saída para mais de dois programas, mas estou começando do zero por enquanto.

$ prog1 | prog2
$ prog1 | prog3
$ prog1 | prog4
...
longda
fonte
Eu acho que o zsh pode fazer isso.
Keith

Respostas:

28

Substituição de processo.

... | tee >(prog2) | ...
Ignacio Vazquez-Abrams
fonte
1
IIRC que é uma extensão do bash e não foi encontrada no padrão POSIX sh.
Simon Richter
6
@SimonRichter Esta é uma extensão do ksh93, também encontrada no bash e no zsh.
Gilles 'SO- stop be evil'
16

Semelhante à resposta de Ignacio, você pode usar um pipe nomeado temporário usando mkfifo(1).

mkfifo /tmp/teedoff.$$; cmd | tee /tmp/teedoff.$$ | prog2 & sleep 1; prog3 < /tmp/teedoff.$$; rm /tmp/teedoff.$$

É um pouco mais detalhado, mas funcionaria em sistemas que não têm substituição de processo, como dash. O sleep 1é para lidar com quaisquer condições de corrida.

Arcege
fonte
6

Há um pequeno utilitário PTEE que faz o trabalho:

prog1 | ptee 2 3 4 2> >(prog2) 3> >(prog3) 4> >(prog4)

Em vez de gravar em arquivos, o ptee grava em todos os fds fornecidos na linha de comando.

ptee faz parte do pipexec .

Andreas Florath
fonte
4

Você não precisa de nenhum bashism ou arquivo especial ou nada disso - nem mesmo no Linux:

% { prog1 | tee /dev/fd/3 | prog2 >&2 ; } 3>&1 | prog3 

{ { printf %s\\t%s\\t%s\\n \
    "this uneven argument list" \
    "will wrap around" to \
    "different combinations" \
    "for each line." "Ill pick out" \
    "a few words" "and grep for them from" \
    "the same stream." | 
 tee /dev/fd/3 /dev/fd/4 | 
 grep combination >&2 ; } 3>&1 |
 grep pick >&2 ; } 4>&1 | 
 grep line

different combinations  for each *line.*  Ill pick out
different combinations  for each line.  Ill *pick* out
different *combinations*  for each line.  Ill pick out

Marquei os resultados grepdestacados para mostrar que não eram apenas três resultados do mesmo fluxo, mas também resultados de grepcorrespondências de processo separadas .

mikeserv
fonte