By default, a command's standard error goes to your terminal. The standard output goes to the terminal or is redirected somewhere (to a file, down a pipe, into backquotes).
Sometimes you want the opposite. For instance, you may need to send a command's standard output to the screen and grab the error messages (standard error) with backquotes. Or, you might want to send a command's standard output to a file and the standard error down a pipe to an error-processing command. Here's how to do that in the Bourne shell. (The C shell can't do this.)
File descriptors 0, 1, and 2 are, respectively, the standard input, standard output, and standard error (article 45.20 explains). Without redirection, they're all associated with the terminal file /dev/tty (45.20). It's easy to redirect any descriptor to any file - if you know the filename. For instance, to redirect file descriptor 2 to errfile, type:
$command
2>errfile
You know that a pipe and backquotes also redirect the standard output:
$command
| ...
$var=`
command
`
But there's no filename associated with the pipe or backquotes, so
you can't use the 2>
redirection.
You need to rearrange the file descriptors without knowing the file
(or whatever) that they're associated with.
Here's how.
Let's start slowly: by sending both standard output and standard error
to the pipe or backquotes.
The Bourne shell operator n
>&
m
rearranges the
files and file descriptors.
It says "make file descriptor n point to the same file as
file descriptor m."
Let's
use that operator on the previous example.
We'll send standard error to the same place standard output is going:
$command
2>&1 | ...
$var=`
command
2>&1`
In both those examples, 2>&1
means "send standard error (file
descriptor 2) to the same place standard output (file descriptor 1)
is going."
Simple, eh?
You can use more than one of those n
>&
m
operators.
The shell reads them left-to-right before it executes the command.
"Oh!" you might say, "To swap standard output and standard error - make stderr go down a pipe and stdout go to the screen-I could do this!"
$command
2>&1 1>&2 | ...
(wrong...)
Sorry, Charlie.
When the shell sees 2>&1 1>&2
, the shell first does 2>&1
.
You've seen that before - it makes file descriptor 2 (stderr)
go the same place as file descriptor 1 (stdout).
Then, the shell does 1>&2
.
It makes stdout (1
) go the same place as stderr
(2
)... but stderr is already going the same place as
stdout, down the pipe.
This is one place the other file descriptors, 3 through 9, come in handy.
They normally aren't used.
You can use one of them as a "holding place," to remember where another
file descriptor "pointed."
For example, one way to read the operator 3>&2
is "make
3
point the same place as 2
."
After you use 3>&2
to grab the location of 2
,
you can make 2
point somewhere else.
Then, make 1
point where 2
used to (where 3
points now).
We'll take that step-by-step below. The command line you want is one of these:
$command
3>&2 2>&1 1>&3 | ...
$var=`
command
3>&2 2>&1 1>&3`
How does it work?
The next four figures
break the second command line (with the backquotes) into the same
steps the shell follows as it rearranges the file descriptors.
You can try these on your terminal, if you'd like.
Each figure adds another n
>&
m
operator and
shows the location of each file descriptor after that operator.
The figures use a grep command reading two files. afone is readable and grep finds one matching line in it; the line is written to the standard output. bfoen is misspelled and so is not readable; grep writes an error message to the standard error. In each figure, you'll see the terminal output (if any) just after the variable-setting command with the backquotes. The text grabbed by the backquotes goes into the shell variable; the echo command shows that text.
By Figure 45.6 the redirection is correct. Standard output goes to the screen, and standard error is captured by the backquotes.
Open files are automatically closed when a process exits.
But it's safer to close the files yourself as soon as you're done with them.
That way, if you forget and use the same descriptor later for something
else (for instance, use F.D. 3 to redirect some other command, or a
subprocess uses F.D. 3), you won't run into conflicts.
Use m
<&-
to close input file descriptor m
and
m
>&-
to close output file descriptor m
.
If you need to close standard input, use <&-
;
>&-
will close standard output.
-