The pipe (|) and tee commands in Linux and Unix (macOS)
Social Share:
Sunday, July 14, 2024 at 5:21 PM | 3 min read
Last modified on Saturday, July 25, 2026 at 12:35 AM
#command line, #linux, #unix, #macOS, #pipe, #tee, #wc, #cat, #history

Photo by Kampus Production on pexels.com
Table of Contents
- What is the tee command?
- Explaining the tee command by example
- The tee command and cat
- The tee command, history and the -a flag
- The tee command, cat, and two file inputs
- The tee command and wc
- Conclusion
- Related Resources
In this article, I discuss the pipe (|) command, aka unnamed pipe, which transmits output of one command as input to another command. It redirects the stdout of one process to the stdin of another for further processing.
What is the tee command?
The tee command reads the stdin and writes it to both stdout and one or more files. According to Geeks for Geeks,
The (tee) command is named after the T-splitter used in plumbing.
Geeks for Geeks also states,
It basically breaks the output of a program so that it can be both displayed and saved in a file. It does both the tasks simultaneously...
Explaining the tee command by example
The best way to describe what tee does is by example. Let's say I ran the following in Terminal from inside a folder called text-files:
ls | tee tee.txt
It would return the following:
duplicates.txt first-named-pipe list-home-directory.txt names1.txt names2.txt tee.txt
And if I ran cat tee.txt, it would yield:
duplicates.txt first-named-pipe list-home-directory.txt names1.txt names2.txt tee.txt
The stdout of the ls command is "piped" into the tee command via | as stdin, and then is both displayed as stdout in Terminal and written in tee.txt as stdout.
And if I ran:
history | tee history.txt
Something like the following would be output in Terminal:
# history.txt ... (truncated) 372 ls | tee -a names1.txt names2.txt tee.txt 373 cat tee.txt 374 ls | tee tee.txt 375 ls 376 cat tee.txt 377 history | tee history.txt
And the same content to Terminal is saved to a newly created file called history.txt as output, thanks to the tee command.
The tee command and cat
If I run cat history.txt | tee history.txt history2.txt, the exact same content is saved to a newly created history2.txt file as stdout to Terminal and history.txt, thanks to the tee command.
# history2.txt ... (truncated) 372 ls | tee -a names1.txt names2.txt tee.txt 373 cat tee.txt 374 ls | tee tee.txt 375 ls 376 cat tee.txt 377 history | tee history.txt
The tee command, history and the -a flag
Let's say I ran more commands, and then wanted to append these new commands added to Terminal history to the bottom of the history.txt file. Running history | tee history.txt would erase all previous content and replace it with the new history. To make sure that the new commands are appended to the end of the file and don't overwrite its previous contents, I run the following in Terminal:
history | tee -a history.txt
This results in the following:
... 378 ls 379 cat history.txt 380 cat history.txt 381 cat history.txt 382 history | tee history.txt
And inside history.txt:
# history.txt ... 378 ls 379 cat history.txt 380 cat history.txt 381 cat history.txt 382 history | tee history.txt
The -a flag, aka --append, is analogous to the output redirect append operator (>>). It appends new data to the end of a file, thereby not overwriting what is already there.
The tee command, cat, and two file inputs
Let's say I run:
cat history.txt | tee history.txt history2.txt
This command returns the complete contents of history.txt in Terminal and copies its content to a newly created history2.txt. And if I run this command again after a bit of time and a few more commands, and add the -a or --append flag:
cat history.txt | tee -a history.txt history2.txt
Running cat again appends history.txt's contents to its previous content, thereby doubling the number of lines in the file. The same goes for history2.txt. Its number of lines doubled as well.
The tee command and wc
The wc command finds the number of lines, words, characters, bytes, and maximum line length of files, in that order. But it does not necessarily find all those items at once.
When I execute:
wc -l history2.txt
it returns the following in Terminal:
804 history2.txt
And when I run:
wc -l history.txt
It produces the following in Terminal:
804 history.txt
If I run the command:
wc history.txt
it produces:
804 2094 21800 history.txt
804 represents the number of (new) lines, 2094 represents the number of words, and 21800 the number of bytes. And if I run the following in Terminal:
wc -L history.txt
It yields:
67 history.txt
67 represents the max length or "width" of a line. In other words, 67 characters (including spaces).
There are other options to choose from for wc and tee, and you can learn more about them by running man wc and man tee in Terminal.
Conclusion
In this piece, I walk through how the pipe and tee commands work together in conjunction with other commands such as cat, wc, and history to create practical instructions applicable in daily workflows. I accompany my explanations with live code snippets and their outputs.
Related Resources
- 3.2.3 Pipelines: gnu.org
- tee(1) — Linux manual page: man7.org
- Count Lines in a File in Bash: baeldung.com
- pipe(2) — Linux manual page: man7.org
- tee command in Linux with examples: Geeks for Geeks