UNIX shell commands return exit statuses or exit codes upon completion, irrespective of whether successful or not. In UNIX, an exit status of 0 indicates successful execution of a command and a non-zero exit status indicates a failure. Some shells (e.g. ksh93) document the various exit statuses and their meanings. So, checking exit statuses of commands is typically done in programs like shell scripts to decide further action to be taken by the script.

However, piped commands or a pipeline (cmd A | cmd B), add a twist to checking exit statuses as by default, most UNIX shells adhere to the POSIX requirement of returning the exit status of the last command in the pipe. Refer the example below:

 

#
# Two commands piped and both commands are successful.
#
$ grep MemTotal /proc/meminfo | awk '{print $2}'; echo "EXIT STATUS = $?"                                                                      
1056836
EXIT STATUS = 0
#
# Two commands piped and first command throws an error.
# Note that the EXIT STATUS is still 0
#
$ grep MemTotal /proc/meminf | awk '{print $2}'; echo "EXIT STATUS = $?"
grep: /proc/meminf: No such file or directory
EXIT STATUS = 0

 

So, checking the exit status of a pipeline as in the above example will cause problems for your script if any of the piped commands other than the last command throw an error. Given below are two solutions (using ksh93 and bash) to solve this problem and ensure a valid exit status check for a pipeline:

SOLUTION 1: Using ksh93 and the pipefail option

The Korn Shell 1993 version ‘g’ point release (ksh93g) introduced a pipefail option which ensures that the exit status of a pipeline will be that of the first command in the pipe that has failed (of course, the exit status of the pipeline will be 0 if all commands in the pipe succeed). Unfortunately, ksh88 is distributed as the default Korn Shell with most UNIX systems (with all Solaris versions I believe) because ksh93 is owned by Lucent and AT&T and there were licensing restrictions. Refer I (Q.14) and III (Q.8) of the Korn shell FAQs at http://kornshell.com/doc/faq.html

An example of how the pipefail option is used is shown below:

 

#
# Check ksh version
#
$ ksh --version
  version         sh (AT&T Research) 93s+ 2008-01-31
#
# Set pipefail option on (it's off by default)
#
$ set -o pipefail
#
# Now, notice the non-zero exit status due to the error in the first command
#
$ grep MemTotal /proc/meminf | awk '{print $2}'; echo "EXIT STATUS = $?"
grep: /proc/meminf: No such file or directory
EXIT STATUS = 2

 

Note: There are other solutions using ksh88 with co-processes and file descriptor manipulation, but those solutions are not script-friendly.

 

SOLUTION 2: Using bash and the PIPESTATUS array

The bash shell uses an array called PIPESTATUS to store the exit statuses of commands in a pipeline.

 

#
# Using the PIPESTATUS array to display exit statuses of both commands in the pipe
#
mrkips@mrkips-laptop:~$ grep MemTotal /proc/meminf | awk '{print $2}'; echo "EXIT STATUS = ${PIPESTATUS[0]}"

grep: /proc/meminf: No such file or directory

EXIT STATUS = 2


mrkips@mrkips-laptop:~$ grep MemTotal /proc/meminf | awk '{print $2}'; echo "EXIT STATUS = ${PIPESTATUS[1]}"

grep: /proc/meminf: No such file or directory

EXIT STATUS = 0

 

Be aware of SIGPIPE

SIGPIPE is a signal sent to a process (that causes the process to terminate) that writes to a pipe when there is nothing to read from the pipe. If you use any of the above mthods to check the exit status of a pipeline and a SIGPIPE is received by one of the commands in the pipeline, then your exit status may not correlate with the success/failure of the pipeline.

For example, in the command,

ls -lrt | head -1

“ls -lrt” writes to a pipe and “head -1” reads from that pipe. Now, “head -1” only requires the first line from the pipe and as soon as it gets it, it terminates and sends a SIGPIPE (signal 13) to “ls -lrt” causing “ls -lrt” to terminate with a non-zero exit code.

 

NOTE:

(1) The how-to above describes how I implemented something and may not be the only method of implementation.

(2) Your rating of this post will be much appreciated. Also, feel free to leave comments.

VN:F [1.9.22_1171]
Rating: +16 (from 16 votes)