How to Use the Command 'pee' (with Examples)
The pee
command is a tool from the moreutils
package that allows you to tee stdin
to multiple pipes. This command is particularly useful when you want to take input from a single source and send it simultaneously to multiple commands or logs, allowing each command to process the same input independently. Unlike tee
, which duplicates data to files and the standard output, pee
specifically duplicates input data to multiple commands.
Use case 1: Run Each Command, Providing Each One With a Distinct Copy of stdin
Code:
pee command1 command2 ...
Motivation:
In complex command-line operations, there are situations where you need multiple utilities to process the same input independently. By using pee
, you can simplify this process by duplicating the stdin
so that each of the provided commands runs concurrently, each receiving the same input. For example, you might want to send a dataset to both a data analysis tool and a logging utility at the same time.
Explanation:
pee
: The main command, indicating the operation to duplicatestdin
.command1
,command2
, …: These represent the list of commands you want to execute concurrently, each receiving a distinct copy ofstdin
.
Example Output:
Suppose you send a simple text stream through pee
to two commands, wc -l
and grep "example"
.
echo -e "line1\nexample line2\nline3" | pee "wc -l" "grep 'example'"
2 # Output from wc -l
example line2 # Output from grep 'example'
Here, each command processes the input independently: wc -l
counts the lines, and grep
searches for the word “example”.
Use case 2: Write a Copy of stdin
to stdout
(Like tee
)
Code:
pee cat command1 command2 ...
Motivation:
Sometimes, you want not only to process input using multiple commands but also to observe the original input being processed directly via stdout
. By inserting cat
as the first command in the sequence, pee
effectively acts like tee
by outputting the original input stream to stdout
while simultaneously directing it to each of the specified commands. This can be particularly beneficial for debugging purposes, as it allows you to see what is being fed into each of the commands.
Explanation:
pee
: The main command to distributestdin
.cat
: Outputs thestdin
tostdout
.command1
,command2
, …: Additional commands to process copies of the input.
Example Output:
When you pipe some text into the command, all specified commands including cat
will process it:
echo "Hello World" | pee cat "tr '[:lower:]' '[:upper:]'"
Hello World # Output from cat
HELLO WORLD # Output from tr
The cat
command outputs the input text as-is to stdout
, while tr
converts it to uppercase.
Use case 3: Immediately Terminate Upon SIGPIPEs and Write Errors
Code:
pee --no-ignore-sigpipe --no-ignore-write-errors command1 command2 ...
Motivation:
When running commands that may produce output too quickly for downstream processes to handle or when working in environments where write errors could occur, it is necessary to react immediately to these issues. By default, pee
ignores SIGPIPEs and write errors, but in some scenarios, for example, with scripts that require strict error handling, you need the command to halt immediately once such a condition is detected. This use-case becomes important to prevent data loss or corruption in sensitive data processing pipelines.
Explanation:
pee
: The command performing the duplication ofstdin
.--no-ignore-sigpipe
: Ensures the process stops immediately if a SIGPIPE signal is received, usually indicating a broken pipe downstream.--no-ignore-write-errors
: Ensures the process stops immediately if a write error occurs, securing operations needing strict reliability.command1
,command2
, …: Commands meant to handle the data stream.
Example Output:
Running a pipeline with these flags can prevent unwanted data mishandling when downstream issue occurs:
(echo "This is a test"; sleep 1) | pee --no-ignore-sigpipe --no-ignore-write-errors "head -n1" "head -n0"
This is a test
In this case, if any command fails to write its output due to a pipe problem, the pee
process will terminate immediately, thus preventing further execution.
Conclusion:
The pee
command serves as a powerful tool for distributing input data to multiple pipelines, allowing versatile and parallel script workflows. Whether you are running complex data processes, debugging, or ensuring strict error handling, pee
offers significant utility by extending the traditional capabilities of tee
to command-line operations.