Redirection and pipes — chaining commands together
Every command's output can be redirected to a file instead of the screen, and one command's output can become another command's input directly. This single idea — pipes — is the actual mechanism behind combining small tools into something more powerful than any one of them alone.
Beginner
3 min read
Every command has input and output streams, even if you don't see them
Every command-line program reads from standard input (stdin) and writes
to standard output (stdout) — normally your keyboard and your terminal
screen, but neither is fixed; both can be redirected somewhere else entirely.
There's also standard error (stderr), a separate stream specifically for
error messages, kept distinct from normal output on purpose.
Redirection: sending output to a file instead of the screen
> writes a command's output to a file, replacing that file's previous
contents entirely; >> appends to the end instead of replacing:
$ ls > filelist.txt # overwrite filelist.txt with the current listing$ echo "new line" >> log.txt # append one line to the end of log.txt
A genuinely common mistake: using > when >> was intended, silently
destroying a file's previous contents instead of adding to it — worth double
checking which one you actually meant, especially in a script that runs
repeatedly.
Pipes: one command's output becomes another's input
The pipe (|) is the single most powerful idea in this lesson: it
connects one command's stdout directly to the next command's stdin, letting
you chain small, focused tools together into a combined operation none of them
could do alone:
$ cat access.log | grep "error" # search a file's contents$ ps aux | grep "python" # find running python processes$ history | grep "docker" # search your own command history$ cat access.log | grep "error" | wc -l # count how many lines matched
Why this is the direct expression of the Unix philosophy
This domain's first lesson mentioned Unix's original design philosophy — small
tools, each doing one thing well, combined together. Pipes are the literal
mechanism that makes that philosophy work in practice: grep doesn't need to
know how to read a log file directly from disk if it can just receive already-
filtered text piped in from cat, and wc (word/line count) doesn't need to
know anything about log files or errors at all — it just counts whatever lines
arrive on its stdin, regardless of where they came from.
A realistic, combined example
Finding the 5 most recent lines in a log file that mention "timeout,"
built entirely from small pieces:
$ cat server.log | grep "timeout" | tail -n 5
cat reads the file; grep filters to only the relevant lines; tail
keeps just the last 5 of those. Each piece is simple and independently
understandable, and the combination does something specific none of them do
individually — exactly the same compositional idea this domain's networking-
adjacent tools (curl, piped into grep or jq for JSON) rely on constantly
in real day-to-day work.