Reputation: 135197
I have a script that I would like to run as
$ myscript < mydata.dat
Inside myscript
I need to fork/pipe STDIN to multiple destinations
#!/usr/bin/env bash
php script1.php > out1
php script2.php > out2
php script3.php > out3
Each one needs a copy of STDIN. Is it possible?
Something like
# obviously this is broken ...
STDIN | php script1.php > out1
STDIN | php script2.php > out2
STDIN | php script3.php > out3
Upvotes: 3
Views: 3307
Reputation: 113814
To copy stdin to several process, use tee
and process substitution:
tee >(script1 > out1) >(script2 >out2) ... | lastscript >outlast
The construct >(...)
is called process substitution. It creates a file-like object that tee
can write. The command inside the parens is executed and whatever tee
writes to it is provides to the command as stdin.
Process substitution is supported by bash, ksh, and zsh. It is not POSIX and will not work under dash.
Let's consider this simple script:
$ cat myscript
#!/bin/bash
tee >(grep 1 >out1) >(grep 2 >out2) | grep 3 >out3
We can run it and verify the results:
$ seq 10 | bash myscript
$ cat out1
1
10
$ cat out2
2
$ cat out3
3
Upvotes: 9
Reputation: 530872
A variation on John1024's answer is to use named pipes in place of process substitution.
mkfifo p1 p2 p3
tee p1 p2 p3 > /dev/null & # or tee p1 p2 > p3 &
php script1 < p1 > out1 &
php script2 < p2 > out2 &
php script2 < p3 > out3 &
wait
rm p1 p2 p3
(Process substitution is effectively, and in some implementations literally, syntactic support for creating, managing, and cleaning up explicit named pipes.)
Upvotes: 3