Mulan
Mulan

Reputation: 135197

How to fork/pipe stdin in bash script?

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

Answers (2)

John1024
John1024

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.

Simple example

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

chepner
chepner

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

Related Questions