[shell] Meaning of $? (dollar question mark) in shell scripts

What does

echo $?

mean in shell programming?

This question is related to shell scripting special-characters

The answer is


This is the exit status of the last executed command.

For example the command true always returns a status of 0 and false always returns a status of 1:

true
echo $? # echoes 0
false
echo $? # echoes 1

From the manual: (acessible by calling man bash in your shell)

$?       Expands to the exit status of the most recently executed foreground pipeline.

By convention an exit status of 0 means success, and non-zero return status means failure. Learn more about exit statuses on wikipedia.

There are other special variables like this, as you can see on this online manual: https://www.gnu.org/s/bash/manual/bash.html#Special-Parameters


$? returns the exit value of the last executed command. echo $? prints that value on console. zero implies a successful execution while non-zero values are mapped to various reason for failure.

Hence when scripting; I tend to use the following syntax

if [ $? -eq 0 ]; then
 # do something
else
 # do something else
fi

The comparison is to be done on equals to 0 or not equals 0.

** Update Based on the comment: Ideally, you should not use the above code block for comparison, refer to @tripleee comments and explanation.


It has the last status code (exit value) of a command.


echo $? - Gives the EXIT STATUS of the most recently executed command . This EXIT STATUS would most probably be a number with ZERO implying Success and any NON-ZERO value indicating Failure

? - This is one special parameter/variable in bash.

$? - It gives the value stored in the variable "?".

Some similar special parameters in BASH are 1,2,*,# ( Normally seen in echo command as $1 ,$2 , $* , $# , etc., ) .


Minimal POSIX C exit status example

To understand $?, you must first understand the concept of process exit status which is defined by POSIX. In Linux:

  • when a process calls the exit system call, the kernel stores the value passed to the system call (an int) even after the process dies.

    The exit system call is called by the exit() ANSI C function, and indirectly when you do return from main.

  • the process that called the exiting child process (Bash), often with fork + exec, can retrieve the exit status of the child with the wait system call

Consider the Bash code:

$ false
$ echo $?
1

The C "equivalent" is:

false.c

#include <stdlib.h> /* exit */

int main(void) {
    exit(1);
}

bash.c

#include <unistd.h> /* execl */
#include <stdlib.h> /* fork */
#include <sys/wait.h> /* wait, WEXITSTATUS */
#include <stdio.h> /* printf */

int main(void) {
    if (fork() == 0) {
        /* Call false. */
        execl("./false", "./false", (char *)NULL);
    }
    int status;
    /* Wait for a child to finish. */
    wait(&status);
    /* Status encodes multiple fields,
     * we need WEXITSTATUS to get the exit status:
     * http://stackoverflow.com/questions/3659616/returning-exit-code-from-child
     **/
    printf("$? = %d\n", WEXITSTATUS(status));
}

Compile and run:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o bash bash.c
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o false false.c
./bash

Output:

$? = 1

In Bash, when you hit enter, a fork + exec + wait happens like above, and bash then sets $? to the exit status of the forked process.

Note: for built-in commands like echo, a process need not be spawned, and Bash just sets $? to 0 to simulate an external process.

Standards and documentation

POSIX 7 2.5.2 "Special Parameters" http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02 :

? Expands to the decimal exit status of the most recent pipeline (see Pipelines).

man bash "Special Parameters":

The shell treats several parameters specially. These parameters may only be referenced; assignment to them is not allowed. [...]

? Expands to the exit status of the most recently executed foreground pipeline.

ANSI C and POSIX then recommend that:

  • 0 means the program was successful

  • other values: the program failed somehow.

    The exact value could indicate the type of failure.

    ANSI C does not define the meaning of any vaues, and POSIX specifies values larger than 125: What is the meaning of "POSIX"?

Bash uses exit status for if

In Bash, we often use the exit status $? implicitly to control if statements as in:

if true; then
  :
fi

where true is a program that just returns 0.

The above is equivalent to:

true
result=$?
if [ $result = 0 ]; then
  :
fi

And in:

if [ 1 = 1 ]; then
  :
fi

[ is just an program with a weird name (and Bash built-in that behaves like it), and 1 = 1 ] its arguments, see also: Difference between single and double square brackets in Bash


From http://www.gnu.org/s/bash/manual/bash.html#Special-Parameters

?
Expands to the exit status of the most recently executed foreground pipeline. 

Outputs the result of the last executed unix command

0 implies true
1 implies false

See The Bash Manual under 3.4.2 Special Parameters:

? - Expands to the exit status of the most recently executed foreground pipeline.

It is a little hard to find because it is not listed as $? (the variable name is "just" ?). Also see the exit status section, of course ;-)

Happy coding.


Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to scripting

What does `set -x` do? Creating an array from a text file in Bash Windows batch - concatenate multiple text files into one Raise error in a Bash script How do I assign a null value to a variable in PowerShell? Difference between ${} and $() in Bash Using a batch to copy from network drive to C: or D: drive Check if a string matches a regex in Bash script How to run a script at a certain time on Linux? How to make an "alias" for a long path?

Examples related to special-characters

How to use tick / checkmark symbol (?) instead of bullets in unordered list? HTML for the Pause symbol in audio and video control How to run mysql command on bash? Which characters need to be escaped when using Bash? Matching special characters and letters in regex jQuery: Check if special characters exists in string Checking if a character is a special character in Java How to display special characters in PHP How should I escape commas and speech marks in CSV files so they work in Excel? grep for special characters in Unix