How would I pass the output of one command to multiple commands?

Quick answer. You can use tee >(what_to_do) >(another_thing_to_do) to keep going with your command for as many different things you want to do.

Example:

Original test file output:

:~$ cat testfile.txt 
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616

Output with tee commands added:

:~$ cat testfile.txt | tee >(tail -1) >(wc) >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
      2      10      91
Serial Number:    TW0XFJWX550854187616

Each command in tee is just normal commands you would use on the command line, like add in >(head -1 | wc) works as well.

:~$ cat testfile.txt | tee >(tail -1) >(head -1 | wc)  >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
      1       7      52
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
Serial Number:    TW0XFJWX550854187616

Or you can also grab the last word of say the last line by using awk with $NF with a wc as well like this:

:~$ cat testfile.txt | tail -1 | tee >(wc) >(awk '{print $NF}')
Serial Number:    TW0XFJWX550854187616
TW0XFJWX550854187616
      1       3      39

NOTE: Adding a | pipe command to the end can override using the multiple commands from the tee command. I have some examples here that I have been testing:

Example 1 (Pipe command pulling all last words):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $NF}'
words
24
5
1

Example 2 (Does not show the output of the wc commands. Pipe command grabbing 3rd word.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $3}'
just

Example 3 (Grabbing the 3rd word of echo line. Tee command.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $3}')
This is just five words
just
24
5
1

Example 4 (Grabbing the last word of the echo line. Tee command.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $NF}')
This is just five words
words
24
5
1

Hope this helps!


You need tee to split the stream into parts. Try:

cat testfile | tee >(wc -l) >(wc -w) >(wc -c) | tail -n 5

Notes:

  • If multiple processes (wc, tail) are all writing to stdout:

    • You might get garbled output.

    • There is no guarantee about the order in which their output will appear. To see this, try sleep 1; wc -w as the second consumer.

  • tee will block if any of its destinations does not consume the stream fast enough. Meaning, the destinations will be fed input at roughly similar speed (modulo the fixed-size buffering). There is no easy fix for this, the only alternative is to save the stream to a file, and feed it to the consumers separately. For wc and tail this is not an issue.

For the last word, it's simpler to do:

echo "some random words" | awk '{print $NF}'

The moreutils package provides the command pee (merge of pipe and tee, what did you think?) which does exactly that.

For your first example, you'd use:

cat testfile | pee wc "tail -n 5"

The second example is more complicated because you want to pass two inputs to the last command. I would probably use awk as the other answers.

Link: https://joeyh.name/code/moreutils/