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. Forwc
andtail
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/