Command exit status – variable $?

Ian! D. Allen – www.idallen.com

Winter 2016 - January to April 2016 - Updated 2018-11-05 17:37 EST

1 Command Exit Status – 0 to 255Indexup to index

When a Unix/Linux command (process) terminates it sets a numeric exit status (also called exit code or return value) between 0 and 255 that is available to the parent process that started (forked) the command.

Normally your shell doesn’t tell you the exit status of commands that it runs, but the shell puts the exit status of the previous command into the shell variable named $?, and you can make the exit status visible using echo $? right after you run the command:

$ date
Thu Nov 19 11:08:05 EST 2015
$ echo "The exit status was $?"
The exit status was 0

An exit status of 0 (zero) normally means “success” – the command worked.

The shell $? variable is set after every command the shell runs, including after running echo (which always succeeds). Note how this works:

$ fgrep 'nosuchthing' /etc/passwd
$ echo "The exit status was $?"
The exit status was 1
$ echo "The exit status was $?"
The exit status was 0

A non-zero exit status normally means something failed or went wrong:

$ rm nosuchfile
rm: cannot remove ‘nosuchfile’: No such file or directory
$ echo "The exit status was $?"
The exit status was 1

$ nosuchcommand
nosuchcommand: command not found
$ echo "The exit status was $?"
The exit status was 127

A non-zero exit status usually means “the command failed”.

2 No standard set of failure codes for all commandsIndexup to index

The meaning of a particular non-zero exit code varies from command to command; there is no standard set of non-zero exit codes that apply across all commands. See the man pages for each command for details.

The only universal standard for command exit codes is that “a zero exit code means success”. Think of exit status as “there is only one way to succeed (only one zero); there are many ways to fail (many non-zero)”.

Some badly-written commands fail but still return zero. Sorry!

Programmers used to other programming languages may find that a command return code of zero meaning “success” and a non-zero exit status meaning “failure” backwards from what they are used to in evaluating arithmetic expressions, where zero means FALSE and anything non-zero means TRUE. Yes; this backwards. Think of command exit status as “there is only one way to succeed (only one zero); there are many ways to fail (many non-zero)”. Don’t get “running commands” confused with “evaluating Boolean expressions”. Shells run commands and check exit statuses; they don’t do math.

3 Checking Exit status using variable $?Indexup to index

On the command line or inside a shell script, after running a command we can use the value of the shell $? variable immediately after a command runs to check the exit status of that command:

$ fgrep "no such text" /etc/passwd
$ echo "The exit status was $?"
The exit status was 1
$ echo "The exit status was $?"
The exit status was 0

The exit status is set after every command, including shell built-in commands. The second use of $? above refers to the successful (zero) exit status of the preceding echo command. If you need to use the exit status of a command more than once, save it in a variable:

$ fgrep "no such text" /etc/passwd
$ status=$?
$ echo "The exit status was $status"
The exit status was 1
$ echo "The exit status was $status"
The exit status was 1

4 Exit status of grep and fgrepIndexup to index

Notable exceptions to this zero-is-success and non-zero-is-failure rule are the searching commands grep and fgrep that return different types of failure:

Examples of success and both types of failure:

$ fgrep "root:" /etc/passwd >/dev/null
$ echo $?
0

$ fgrep "no such text" /etc/passwd
$ echo $?
1

$ fgrep "anything" nosuchfile
fgrep: nosuchfile: No such file or directory
$ echo $?
2

5 Setting an exit status in a scriptIndexup to index

A shell script is run by a shell process, and that shell process has its own exit status when it finishes reading your script. Normally, a shell script exits with the status of the last command run inside the script:

$ cat test.sh
#!/bin/sh -u
fgrep 'no such text' /etc/passwd

$ ./test.sh
$ echo "The exit status of the script is $?"
The exit status of the script is 1

You can exit a shell script and set the exit status of its shell process using an explicit exit statement with a number argument between 0 and 255:

$ cat test.sh
#!/bin/sh -u
exit 99

$ ./test.sh
$ echo "The exit status of the script is $?"
The exit status of the script is 99

An exit statement inside a shell script causes the script to stop running and the shell process running it to terminate.

6 The true and false commandsIndexup to index

The command true does nothing except return a good (zero) exit status.

The command false does nothing except return a bad (non-zero) exit status.

$ true ; echo $?
0
$ false ; echo $?
1

These commands are often built in to your shell, but they are also separate executable programs with their own man pages, and sometimes the commands even have options. Both commands usually ignore most arguments, but the built-in versions may not handle options exactly the same way as the external versions:

bash$ type true
true is a shell builtin
bash$ true --help                          # built-in version has no options

bash$ which true
/bin/true
bash$ /bin/true --help                     # external version has output from options
Usage: /bin/true [ignored command line arguments]
  or:  /bin/true OPTION
[... more help output ...]

These commands are never used interactively; they are most useful in shell scripts.

7 Using script logic to check exit statusIndexup to index

You need to understand shell script control flow for this section.

Scripts can use control flow statements to check the exit status of commands to know whether the commands worked and whether the script should continue processing or issue an error message and stop:

#!/bin/sh -u
fgrep "$1" /etc/passwd                    # look for argument in passwd
status=$?                                 # save the status for later
if [ "$status" = 0 ] ; then
    echo 1>&2 "$0: Success status $status - found the string '$1' in passwd"
    exit "$status"
fi
if [ "$status" = 1 ] ; then
    echo 1>&2 "$0: Not found status $status - did not find '$1' in passwd"
    exit "$status"
fi
if [ "$status" = 2 ] ; then
    echo 1>&2 "$0: File error status $status - unknown error with passwd"
    exit "$status"
fi

The above script uses some conditional logic if statements to test the exit status saved in the $status variable. The script checks the saved exit status three times. It issues different messages on stderr depending on whether the saved exit status of the fgrep command was 0, 1, or 2. The script itself uses an exit statement with a $status number argument to cause the shell process to exit with exactly the same exit status as the fgrep command.

Author: 
| Ian! D. Allen, BA, MMath  -  idallen@idallen.ca  -  Ottawa, Ontario, Canada
| Home Page: http://idallen.com/   Contact Improv: http://contactimprov.ca/
| College professor (Free/Libre GNU+Linux) at: http://teaching.idallen.com/
| Defend digital freedom:  http://eff.org/  and have fun:  http://fools.ca/

Plain Text - plain text version of this page in Pandoc Markdown format

Campaign for non-browser-specific HTML   Valid XHTML 1.0 Transitional   Valid CSS!   Creative Commons by nc sa 3.0   Hacker Ideals Emblem   Author Ian! D. Allen