
Questions regarding this column should be sent to the author
at ray@cse.ucsc.edu.
Can A Pipe Have More Than One Exit?
By Ray Swartz
Question: I was a subscriber of UnixWorld and now I
am a reader of UnixWorld Online. I'm a Korn shell user and I
have a problem in the execution of the following pipe:
command1 | command2
How do I save the execution status of the first command
(command1) in the pipe line? I know that the exit
status, after the execution of a command is saved in
$?, but in the previous expression this variable
takes the exit status of the second command in the pipe line
(command2).
Rafael Pascual / Madrid, Spain
Answer: You are correct that the exit status of a
pipeline is reported as the exit status of the last command in
the pipeline. The exit status is reported by the shell as it
executes the pipeline. It is the shell that stores the pipe's
exit status in the $? variable.
What happens to the exit status of the first (or other)
command? It is ignored by the shell. However, you should be
able to capture it with a little ingenuity.
A command's exit status is the value returned to the process
that called it. A command can only have one exit status because
only a single integer is reserved by the UNIX kernel for a
process's exit status. Because a pipeline has, at least, two
commands, the designers of the UNIX system had to decide which
exit status to report back to the shell for the command that
implements a pipeline. The one they chose was the exit status of
the command at the tail of the pipeline.
You can capture the exit status of the first (or other)
command in a pipeline by running that command inside a shell
script whose sole task is running the command and then reporting
the exit status of the command executed.
Here is the code for one such script, which we'll name
exit.report:
#!/bin/ksh
"$@"
echo "Exit status of command ("$@") was " $? >&2
This script executes the command line specified on its
invocation command line and reports the command exit status to
the standard error file to separate it from standard output,
which could be redirected to a file or into a pipe.
The "$@" construct represents all the command
line arguments enclosed in double quotes, so that substitution is
performed, but the result is protected from further processing by
the shell. The >&2 construct, which is
shorthand for 1>&2, causes the output of
echo to sent to standard error (which is associated
with the terminal).
Here the exit.report script has been passed a
simple command line (not a pipe line):
$ exit.report cat exit.report
#!/bin/ksh
"$@"
echo "Exit status of command ("$@") was " $? >&2
Exit status of command (cat exit.report) was 0
$ []
which it executes and then displays its exit status (0 in this
example) because the cat command succeeded.
Here is an example with a pipeline:
$ exit.report cat exit.report | wc
Exit status of command (cat exit.report) was 0
3 12 64
$ []
This command line sends the output of the cat
exit.report command to wc via the pipeline to
give the count report. The exit status output from
exit.report is sent to the standard error, not into
the pipeline, so it is displayed on the terminal before the
output from wc.
Here is another example where the command at the head of the pipeline
fails:
$ exit.report grep Answer exit.report | wc -l
exit.report grep Answer exit.report | wc -l
Exit status of command (grep Answer exit.report) was 1
0
$ []
exit.report also works in the middle of a pipeline:
$ cat exit.report | exit.report grep Answer | wc -l
Exit status of command (grep Answer) was 1
0
$ []
|