Streams, pipes and redirection
Redirection and pipes: the three standard file descriptors, how to send each one somewhere else, and the two commands — tee and xargs — that exist because pipes alone cannot do everything.
Lesson 4 of 8 in objective 103. GNU and Unix commands, part of LPIC-1 Exam 101-500.
Three descriptors, and the numbers matter
Every process starts with standard input (descriptor 0), standard output (1) and standard error (2). > redirects standard output to a file, truncating it; >> appends; < takes standard input from a file. Errors are not redirected by > at all, which is why a command can appear to write nothing to its log file and still print a message on the terminal — that message went to descriptor 2.
2> redirects standard error, and 2>&1 makes descriptor 2 point at wherever descriptor 1 currently points. Order is everything: command > file 2>&1 sends both to the file, while command 2>&1 > file sends errors to the terminal, because at the moment 2 was pointed at 1, descriptor 1 was still the terminal. &> is the bash shorthand for both. /dev/null is the sink that discards anything written to it. Nothing forces the two streams together either: backup.sh > /var/log/backup.out 2> /var/log/backup.err gives each its own file, which is how a nightly job keeps a result log worth reading and an error log worth alerting on.
The other direction is asked less often than it deserves. sort < names.txt has the SHELL open the file and hand sort an already-open descriptor 0, so the command reads a stream and never learns the file's name; 0< is the same operator with the descriptor spelled out, exactly as 1> is the long spelling of >. The difference shows in anything that labels its results: wc -l /var/log/syslog prints the count and the file name after it, wc -l < /var/log/syslog prints the bare number, which is the form a script wants inside $( ). set -o noclobber, also spelled set -C, makes the shell refuse a plain > onto a file that already exists — the guard against typing > where >> was meant — and >| overrides it for one redirection without switching the option off. Because it is a property of the shell doing the redirecting rather than of the file, it never stops a program that opens the file itself, tee included.
Pipes, tee and xargs
A pipe connects one command's standard output to the next command's standard input, and the whole pipeline runs concurrently rather than one command finishing before the next starts. Standard error is not piped, which again is why errors appear on the terminal in the middle of a paged output.
tee writes its input to a file AND passes it on, so a pipeline can be logged without breaking it; tee -a appends. That is what it is for: dmesg | tee boot.log puts the kernel ring buffer on the screen and in a file in one pass, where dmesg > boot.log would give you the file and nothing to read. xargs solves the opposite problem: some commands, notably rm and grep, take file names as ARGUMENTS rather than on standard input, so find . -name "*.log" | xargs rm turns lines into arguments. Pairing find -print0 with xargs -0 is the version that survives file names containing spaces.
xargs is one of two ways across that gap and command substitution is the other. $(command) runs the command, captures its standard output and drops the text into the command line before the outer command is run at all, so kill $(pgrep httpd) reaches kill as kill 812 813 814. Use it when the list is short and known; use xargs when it might be long enough to overflow the argument list, or when -0 is needed for names with spaces in them. What does not work is pgrep httpd | kill, and the reason is the same one xargs exists for: kill reads its arguments and never looks at standard input.
The other thing worth knowing about tee is why it turns up with sudo. A redirection is performed by the SHELL parsing the line, before anything is run, so sudo echo text > /etc/sysctl.d/99-fw.conf opens the file as the unprivileged shell and fails there — sudo is never consulted, because the part that needed privilege was not the part sudo was applied to. echo text | sudo tee /etc/sysctl.d/99-fw.conf moves the opening into a privileged process instead, and sudo tee -a is the appending version. sudo sh -c "echo text > /etc/sysctl.d/99-fw.conf" works for exactly the same reason: this time the shell doing the redirecting is itself the privileged one.
A here-document feeds literal text to a command's standard input: command <<EOF, then lines, then EOF on a line of its own. It is how a script supplies multi-line input without a temporary file. A here-STRING, command <<<"text", is the one-line version.
dmesg | tee boot.log | grep -i error[ 3.2] usb 2-1: device descriptor read/64, error -71the whole buffer is in boot.log; only errors reached the screenmake 2>&1 | tee build.logboth streams logged: 2>&1 comes before the pipemake > build.log 2>&1both to the filemake 2>&1 > build.logerrors to the terminal — 1 was still the terminal thenbackup.sh > /var/log/backup.out 2> /var/log/backup.errtwo streams, two files: they need not end up together
Worth carrying in
- >
- Redirect standard output, truncating the target. >> appends.
- 2>
- Redirect standard error.
- 2>&1
- Point standard error at wherever standard output currently goes. Order matters.
- &>
- Bash shorthand for both streams to one place.
- /dev/null
- Discards everything written to it.
- tee -a
- Write to a file and pass the stream on. -a appends.
- xargs -0
- Turn input lines into command arguments. -0 pairs with find -print0.
- <<EOF
- Here-document: literal lines fed to standard input until the delimiter.
- < file
- Standard input from a file.
wc -l < fileprints a bare number;wc -l filelabels it. - $(command)
- Substitute a command's output into the command line — for
kill,rmand anything else wanting arguments. - >|
- Overwrite despite
set -o noclobber, which otherwise refuses a plain > onto an existing file.
What the exam does with this
- command > file 2>&1 and command 2>&1 > file do different things. This is asked directly.
- Pipes carry standard output only. Sending errors down a pipe needs 2>&1 first.
xargsexists because some commands do not read file names from standard input.kill $(pgrep httpd)works andpgrep httpd | killdoes not: substitution builds an argument list, a pipe feeds standard input, andkillreads only the first.- The shell performs the redirection, so
sudo cmd > /etc/filefails andcmd | sudo tee /etc/filesucceeds. That asymmetry is a question on its own.
- Objective
- 103. GNU and Unix commands
- Share of the exam
- 43.33% (the whole objective)
- Questions in this lesson
- 20
- Signed for by a person
- 0
Partly checked. None of the 20 questions here has been read against the cited source by a person. 20 questions have been checked against their cited clause by an automated pass — which is not the same thing, and is not a signature.
Only questions a person has signed for are used in mock exams here. That is the whole difference between the two kinds of checking above.
How these questions are written — where each question comes from, what the verification ledger records, and what happens when one is found wrong.
Drill this lesson
A lesson is one sitting: the trainer draws a short run from these questions alone and spaces the ones you get wrong.
Practise Streams, pipes and redirection
Questions in this lesson
- Select the TWO true statements about output redirection in bash. machine-checked
- The pipeline `find . -name '*.tmp' | xargs rm` fails on file names that contain spaces, because xargs treats each word as a separate argument. Which form handles those names correctly? machine-checked
- Inside a script you want to feed several lines of text that are written directly in the script, ending at a marker word, to a command's standard input. Which redirection operator introduces that construct? machine-checked
- Type the complete command line that runs `dmesg` so that its output appears on the terminal and is written to the file boot.log at the same time. Use a pipe and the standard tool for this. machine-checked
- A cron entry runs a maintenance script under /bin/sh (dash on this Debian host) and must never generate mail: neither its normal output nor its error messages may reach cron. Which ending to the cron command line discards both streams reliably on that shell? machine-checked
- A nightly backup script should record its progress messages in /var/log/backup.out and its error messages in a separate file, /var/log/backup.err. Which command line does that? machine-checked
- As an unprivileged user you run `sudo echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-fw.conf` and the shell answers with a permission error, even though sudo works for other commands. Which command line writes the file successfully? machine-checked
- A build is run as `make 2>&1`. Every line of the combined stream must be added to build.log, which already holds the output of earlier builds and must not lose it, and the same complete stream must still reach `grep -i warning`. Which pipeline does this? machine-checked
- The file list.txt holds one file name per line. For each name you need to run `mv <name> /archive/`, so the name from the input has to appear before the destination, not at the end of the command line. Which command line does that? machine-checked
- In a cleanup script the line `grep -l OBSOLETE *.conf | xargs rm --` occasionally fails with `rm: missing operand`, because grep matches nothing and GNU xargs runs rm once anyway with no file names. Which GNU xargs option stops the command from being run at all when the input is empty? machine-checked
- A long compile prints diagnostics on standard error. `make | grep -i error` shows nothing useful, because the error lines scroll past on the terminal instead of entering the pipe. Which command line passes both output streams through grep? machine-checked
- You want to send a signal to every httpd process, using the process IDs that `pgrep httpd` prints, on one command line. kill takes its PIDs as arguments, not on standard input. Which construct places the output of one command into the argument list of another? machine-checked
- A script must store the number of lines in /var/log/syslog in a variable, so the output has to be the bare number with no file name after it. Which command produces exactly that? machine-checked
- The shell has been started with `set -o noclobber`. The command `sort names.txt > sorted.txt` now fails, reporting that it cannot overwrite the existing file. Which command replaces the contents of sorted.txt without switching the option off? machine-checked
- An hourly job is started from cron. Its normal output should keep going to cron as usual, while its error messages must accumulate in /var/log/job.err so that the previous hours' messages survive. Which redirection belongs on the command line? machine-checked
- Select the THREE true statements about GNU xargs. machine-checked
- Select the TWO true statements about tee and about writing files from a pipeline. machine-checked
- Type the command, with no options or arguments, that reads items from standard input and builds command lines from them so that another program receives them as arguments. machine-checked
- Searching the whole filesystem as an ordinary user buries the results under "Permission denied" notices from directories you cannot read. Type the complete command line that runs `find / -name core` and discards only those notices, leaving the matched paths on the terminal. machine-checked
- `sort` can take a file name as an operand, but here it must receive the contents of names.txt on its standard input instead. Type the complete command line that runs `sort` with its standard input redirected from names.txt. machine-checked
Practise Streams, pipes and redirection