The pipe (|) and tee commands in Linux and Unix (macOS)

Sunday, July 14, 2024 at 5:21 PM | 3 min read

Last modified on Saturday, July 25, 2026 at 12:35 AM

, , , , , , , ,

Close-up of a hand placing a golf ball on a tee in sunlight, outdoors.

Photo by Kampus Production on pexels.com

Table of Contents

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.