Can I chain multiple commands and make all of them take the same input from stdin? Can I chain multiple commands and make all of them take the same input from stdin? unix unix

Can I chain multiple commands and make all of them take the same input from stdin?


For this example, you should use awk as semiuseless suggests.

But in general to have N arbitrary programs read a copy of a single input stream, you can use tee and bash's process output substitution operator:

tee <food_expenses.txt \  >(grep "coffee" >coffee.txt) \  >(grep "tea" >tea.txt) \  >(grep "honey cake" >cake.txt)

Note that >(command) is a bash extension.


The obvious question is why do you want to do this within one command ?

If you don't want to write a script, and you want to run stuff in parallel, bash supports the concepts of subshells, and these can run in parallel. By putting your command in brackets, you can run your greps (or whatever) concurrently e.g.

$ (grep coffee food_expenses.txt > coffee.txt) && (grep tea food_expenses.txt > tea.txt) 

Note that in the above your cat may be redundant since grep takes an input file argument.

You can (instead) play around with redirecting output through different streams. You're not limited to stdout/stderr but can assign new streams as required. I can't advise more on this other than direct you to examples here


I like Stephen's idea of using awk instead of grep.

It ain't pretty, but here's a command that uses output redirection to keep all data flowing through stdout:

cat food.txt | awk '/coffee/ {print $0 > "/dev/stderr"} {print $0}'     2> coffee.txt | awk '/tea/ {print $0 > "/dev/stderr"} {print $0}'     2> tea.txt

As you can see, it uses awk to send all lines matching 'coffee' to stderr, and all lines regardless of content to stdout. Then stderr is fed to a file, and the process repeats with 'tea'.

If you wanted to filter out content at each step, you might use this:

cat food.txt | awk '/coffee/ {print $0 > "/dev/stderr"} $0 !~ /coffee/ {print $0}'     2> coffee.txt | awk '/tea/ {print $0 > "/dev/stderr"} $0 !~ /tea/ {print $0}'     2> tea.txt