Shell FluencyLesson 2 of 4
Redirection and pipes
Send output to files, keep errors apart from results, and chain small commands into pipelines.
>>>2>&><|teexargs/dev/null
After this lesson you can
- Redirect standard output, standard error and standard input, together or separately.
- Append instead of overwrite, and avoid destroying a file by accident.
- Build pipelines with tee, xargs and grep to answer a question in one line.
The idea
Every command has three standard streams: input (0, normally your keyboard), output (1, normally the screen) and errors (2, also the screen). Redirection points a stream somewhere else. A pipe connects the output of one command directly to the input of the next, which is how Linux builds big tools from small ones.
The rule to remember: the shell sets up redirection before it starts the command, so > empties the target file even if the command then fails. That is why sort file > file leaves you with an empty file.
| Operator | Meaning |
|---|---|
> file | Send output to file, replacing it |
>> file | Append output to file |
2> file | Send errors to file |
&> file | Send output and errors to file (bash) |
2>&1 | Send errors to wherever output goes |
< file | Read input from file |
a | b | Feed the output of a into b |
Try it
cd ~/lab
ls /etc/hostname /nonexistent > ok.txt 2> err.txt
cat ok.txt err.txt
/etc/hostname
ls: cannot access '/nonexistent': No such file or directory
find /etc -name 'ssh*' > found.txt 2> /dev/null
wc -l found.txt
7 found.txt
Order matters with 2>&1: it means “make stream 2 point where stream 1 points right now”, so it goes after the >.
ls /etc/hostname /nonexistent > both.txt 2>&1
cat both.txt
ls: cannot access '/nonexistent': No such file or directory
/etc/hostname
Pipelines
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn
16 /sbin/nologin
3 /bin/bash
1 /bin/sync
1 /sbin/shutdown
1 /sbin/halt
tee writes its input to a file and passes it on, so you can save the middle of a pipeline. xargs turns lines on its input into arguments of another command.
find /etc -maxdepth 1 -name '*.conf' -readable 2>/dev/null | tee confs.txt | head -3
xargs wc -l < confs.txt | tail -1
/etc/resolv.conf
/etc/sudo.conf
/etc/nsswitch.conf
1217 total
Going further
A here-document feeds several lines to a command without a temporary file, which is how you write a config file from a script:
cat > ~/lab/motd.txt <<'EOT'
Welcome to rhel10.
Authorised use only.
EOT
cat ~/lab/motd.txt
Welcome to rhel10.
Authorised use only.
Quote the delimiter ('EOT') to stop the shell expanding $variables inside the text. sudo and redirection do not mix: in sudo echo x > /etc/file the redirection is done by your shell, not by root. Use echo x | sudo tee /etc/file instead.
Practice
0 of 5 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
Overwrite, then append
In
~/lab, write the date tolog.txt, then add the host name to the same file without losing the date. Show the file.Check your result
cat ~/lab/log.txtprints two lines: a date, then the host name.Hint
>replaces the file.>>adds to the end.Solution
mkdir -p ~/lab && cd ~/lab date > log.txt hostname >> log.txt cat log.txt - Practice
Separate results from errors
Run
ls /etc/hostname /nonexistentso the successful line goes took.txtand the error message goes toerr.txt. Neither may appear on screen.Check your result
cat ok.txt err.txtok.txtholds/etc/hostname.err.txtholdsls: cannot access '/nonexistent': No such file or directory.Hint
Standard output is file descriptor 1, standard error is 2.
2>redirects only stderr.Solution
ls /etc/hostname /nonexistent > ok.txt 2> err.txt cat ok.txt err.txt - Practice
Keep the results, silence the errors
Run
find /etc -name 'ssh*'as a normal user. Send the results tofound.txt, and throw away the "Permission denied" errors so they neither show on screen nor land in the file. Count the lines infound.txt.Check your result
wc -l found.txtprints a number greater than zero and no error appears on screen.grep -c denied found.txtprints0.Hint
/dev/nulldiscards everything written to it. Redirect only stream 2 there.Solution
find /etc -name 'ssh*' > found.txt 2> /dev/null wc -l found.txt grep -c denied found.txt - Practice
Top three shells in use
From
/etc/passwd, print the three most common login shells, most common first, each with its count. One pipeline.Check your result
Output is three lines, each a count followed by a shell path, with the biggest count first, for example
16 /sbin/nologin.Hint
cut -d: -f7takes the shell field,sortthenuniq -ccounts,sort -rnorders,head -3trims.Solution
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn | head -3 - Challenge
Save and show; run a command per result
List the files directly in
/etcwhose names end in.confand that you can read. Show the first five on screen and save the full list toconfs.txtin the same command. Then, using the saved list, print the number of lines of every one of those files, largest last.Check your result
confs.txthas the full list. The second command prints a line count for each file and ends with atotalline, with the biggest file just before it.Hint
teecopies its input to a file and to the screen.xargs wc -lturns lines of file names into arguments.Solution
find /etc -maxdepth 1 -name '*.conf' -readable 2>/dev/null | tee confs.txt | head -5 xargs wc -l < confs.txt | sort -n