Shell, explained

What does the pipe | do in the terminal?

ls | grep .txt | wc -l

The pipe | connects two commands: everything the first one prints becomes the input of the second. In ls | grep .txt | wc -l, ls lists the files, grep keeps only the names containing .txt, and wc -l counts what is left.

Three commands, one stream of lines

Tap a command or a | to see its part. grep drops the two lines without .txt; wc -l counts the three that reach it.

$

Tap a part of the command to find it below

$ ls
›notes.txt
·photo.png
›report.txt
·song.mp3
›todo.txt
|

grep keeps 3 of 5 lines

2 dropped

× photo.png× song.mp3

$ grep .txt
notes.txt
report.txt
todo.txt
|

3 lines flow into wc

$ wc -lOUTPUT
3
Tap any part of the command to see what it does

Part by part

ls
Lists the files in the current folder. Into a pipe it prints one name per line.
|
Connects the output of ls to the input of grep. Nothing is shown on screen in between.
grep .txt
Keeps only the lines that contain .txt (the dot means “any character”, so it is a loose match).
|
Sends the lines grep kept on to wc.
wc -l
Counts the lines it receives and prints the number.

Common mistakes

Piping into a command that does not read input

ls | echo prints an empty line: echo only prints its arguments and ignores what comes down the pipe. To turn lines into arguments, use xargs (ls | xargs echo).

Expecting errors to go through the pipe

Only normal output (stdout) goes down a pipe. Error messages go straight to the screen unless you add 2>&1.

Try it

$ ls | grep .txt

See which names grep keeps.

$ ls | grep '\.txt$' | wc -l

A stricter match: names that end in .txt.

$ history | grep git | tail -5

Your last five git commands.

Questions

Do the commands in a pipeline run one after another?

No, they start at the same time. Each line moves on as soon as it is printed, which is why tail -f app.log | grep ERROR shows errors live. Commands like sort and wc still have to wait for all of their input before they can print.

What is the difference between | and >?

| sends output to another command. > sends it to a file. ls | wc -l counts the files; ls > files.txt saves the list.

Why does ls print one name per line in a pipe?

ls checks whether it is writing to a terminal. On screen it uses columns; into a pipe or a file it prints one name per line, which is easier for other commands to read.

Terminaster

Ask about any command and get a picture like this one.

The Terminaster tutor draws these visuals for your own questions, then turns what you learned into spaced-repetition cards so it sticks.