Read

Module 3 · Text, redirection and pipes

Redirecting input and error: <, 2>, 2>&1

The three standard streams by number, how to feed a file into a command, and how to catch or silence error messages.

What you will learn

  • Name the three standard streams and their file descriptor numbers 0, 1 and 2.
  • Feed a file to a command's standard input with <.
  • Redirect error output with 2> and merge it into stdout with 2>&1, in the right order.

Every program starts life with three open channels, numbered by the kernel: 0 is standard input (stdin), where it reads from; 1 is standard output (stdout), where normal results go; 2 is standard error (stderr), where complaints go. In a terminal all three are wired to the same screen and keyboard, which hides the fact that they are separate. Redirection lets you rewire each one individually.

Why two output streams

The separation exists so that errors do not pollute data. If ls printed No such file on stdout, a listing you saved with > would contain error text mixed with file names. Because errors go to stream 2, ls * > list.txt writes only real names into the file and the error still appears on your screen, where you can see it. Well-behaved programs follow this rule, and you should too in your own scripts: echo "something failed" >&2.

Redirecting input with <

command < file makes the command read file as its stdin. Many tools accept a file name as an argument anyway, so sort < data.txt and sort data.txt give the same result; the difference shows in the output of tools like wc, which prints the file name when given one as an argument but only the number when reading stdin. That makes wc -l < file the cleanest way to get a bare count.

Redirecting errors with 2>

Put the stream number right before the arrow: 2> errors.txt sends stderr to a file, 2>> errors.txt appends, and 2> /dev/null throws it away (/dev/null is a device that swallows everything written to it). There is no space between 2 and >; 2 > file would pass the number 2 as an argument to the command.

Merging both with 2>&1

2>&1 means "make stream 2 go wherever stream 1 goes right now". To capture everything a command says into one file, write command > all.txt 2>&1: first stdout is pointed at the file, then stderr is pointed at the same place. The order matters. command 2>&1 > all.txt first copies stderr to the terminal (where stdout still points), and only then moves stdout to the file, so the errors stay on screen.

~% touch exists.txt
~% ls exists.txt nope.txt
ls: nope.txt: No such file or directory
exists.txt
~% ls exists.txt nope.txt > out.txt
ls: nope.txt: No such file or directory
~% cat out.txt
exists.txt
~% ls exists.txt nope.txt 2> err.txt
exists.txt
~% cat err.txt
ls: nope.txt: No such file or directory
~% ls exists.txt nope.txt > all.txt 2>&1
~% cat all.txt
ls: nope.txt: No such file or directory
exists.txt
~% ls exists.txt nope.txt 2>/dev/null
exists.txt
~% wc -l < all.txt
2
SyntaxMeaning
< filestdin reads from file
> filestdout to file (overwrite)
2> filestderr to file (overwrite)
2>> filestderr appended to file
> file 2>&1both streams to file
2>&1 \| cmdboth streams into a pipe (next lesson)
>&2send stdout to stderr (for your own error messages)

Commands in this lesson

CommandWhat it does
command < fileRead file as the command's standard input.
command 2> fileWrite error messages (stderr) to file.
command 2>> fileAppend error messages to file.
command 2> /dev/nullDiscard error messages.
command > file 2>&1Send both stdout and stderr to file.
echo msg >&2Print msg on stderr instead of stdout.
wc -l < fileCount lines without printing the file name.

Quiz

  1. Which file descriptor number is standard error?

    • 0
    • 1
    • 2
  2. What does `ls /nope 2> /dev/null` show on the screen?

    • The error message, as usual
    • Nothing: the error was discarded
    • The content of /dev/null
  3. Which command puts both normal output and errors into out.txt?

    • `cmd 2>&1 > out.txt`
    • `cmd > out.txt 2>&1`
    • `cmd > out.txt 2> out.txt`
  4. What is the difference between `wc -l data.txt` and `wc -l < data.txt`?

    • None at all
    • The first prints the count and the file name; the second prints only the count
    • The second one fails because wc does not read stdin
  5. In your own script, how do you print a warning so it does not get mixed with the data on stdout?

    • `echo warning >&2`
    • `echo warning 2>`
    • `echo warning < 2`

Practice

  1. /root/lab/l23/noisy is a small program that prints `working on it` on stdout and `warning: config file missing` on stderr. Run it so that only the warning is saved in /root/lab/l23/errors.txt while the normal output still appears on screen.

  2. Run /root/lab/l23/noisy again, this time capturing BOTH its normal output and its warning in a single file, /root/lab/l23/all.txt.

  3. /root/lab/l23/numbers.txt holds a few numbers, one per line, out of order. Feed it to sort through input redirection (<) and save the sorted result in /root/lab/l23/sorted.txt.

Open this lesson in the app to do the tasks in a real Linux machine and have them checked.