Search code examples
bashpipestdin

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

Solution

  • 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