Czy istnieje sposób na potokowanie wyniku jednego programu do dwóch innych programów?

28

Przepraszam, jeśli to głupie pytanie, ale staram się osiągnąć coś takiego, ale w jednym wierszu:

$ prog1 | prog2
$ prog1 | prog3

Zasadniczo chcę wykonać prog1 i przesłać dane wyjściowe do prog2 i prog3 osobno (nie łańcuchowo). Na początku próbowałem użyć tee, ale to nie wydawało się właściwe, ponieważ zrzucało dane wyjściowe do pliku (co nie jest tym, czego chcę).

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

W pewnym momencie prawdopodobnie chciałbym rozszerzyć to na przesyłanie danych wyjściowych do więcej niż dwóch programów, ale na razie zaczynam od prostych.

$ prog1 | prog2
$ prog1 | prog3
$ prog1 | prog4
...
longda
źródło
Myślę, że Zsh może to zrobić.
Keith,

Odpowiedzi:

28

Zastąpienie procesu.

... | tee >(prog2) | ...
Ignacio Vazquez-Abrams
źródło
1
IIRC, który jest rozszerzeniem bash i nie znajduje się w standardowym sh POSIX.
Simon Richter,
6
@ SimonRichter To jest rozszerzenie ksh93, również znalezione w bash i zsh.
Gilles „SO- przestań być zły”
16

Podobnie do odpowiedzi Ignacio, możesz użyć tymczasowego nazwanego potoku za pomocą mkfifo(1).

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

Jest to trochę bardziej szczegółowe, ale działałoby na systemach, które nie mają substytucji procesów, takich jak dash. Ma sleep 1poradzić sobie w każdych warunkach wyścigowych.

Arcege
źródło
6

Istnieje mały ptee, który wykonuje zadanie:

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

Zamiast pisać do plików, ptee zapisuje na wszystkich dyskach fds podanych w wierszu poleceń.

ptee jest częścią pipexec .

Andreas Florath
źródło
4

Nie potrzebujesz żadnych bashizmów, specjalnych plików ani żadnego z nich - w każdym razie nie w Linuksie:

% { 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

Oznacziłem gwiazdką grepwyróżnione dla mnie wyniki, aby pokazać, że były to nie tylko trzy wyniki z tego samego strumienia, ale także wynik oddzielnych grepdopasowań procesów.

mikeserv
źródło