What is the $? (dollar question mark) variable in shell scripting?

ShellScripting

Shell Problem Overview


I'm trying to learn shell scripting, and I need to understand someone else's code. What is the $? variable hold? I can't Google search the answer because they block punctuation characters.

Shell Solutions


Solution 1 - Shell

$? is used to find the return value of the last executed command. Try the following in the shell:

ls somefile
echo $?

If somefile exists (regardless whether it is a file or directory), you will get the return value thrown by the ls command, which should be 0 (default "success" return value). If it doesn't exist, you should get a number other then 0. The exact number depends on the program.

For many programs you can find the numbers and their meaning in the corresponding man page. These will usually be described as "exit status" and may have their own section.

Solution 2 - Shell

That is the exit status of the last executed function/program/command. Refer to:

Solution 3 - Shell

A return value of the previously executed process.

> 10.4 Getting the return value of a program > > In bash, the return value of a program is stored in a special variable > called $?. > > This illustrates how to capture the return value of a program, I > assume that the directory dada does not exist. (This was also > suggested by mike) > > #!/bin/bash > cd /dada &> /dev/null > echo rv: $? > cd $(pwd) &> /dev/null > echo rv: $?

See Bash Programming Manual for more details.

Solution 4 - Shell

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:

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: https://stackoverflow.com/questions/13542832/what-is-the-difference-between-single-and-double-square-brackets-in-bash/31366734#31366734

Solution 5 - Shell

$? is the result (exit code) of the last executed command.

Solution 6 - Shell

It is the returned error code of the last executed command. 0 = success

Solution 7 - Shell

$? is the exit status of a command, such that you can daisy-chain a series of commands.

Example

command1 && command2 && command3

command2 will run if command1's $? yields a success (0) and command3 will execute if $? of command2 will yield a success

Solution 8 - Shell

The exit code of the last command ran.

Solution 9 - Shell

It is well suited for debugging in case your script exit if set -e is used. For example, put echo $? after the command that cause it to exit and see the returned error value.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid MulderView Question on Stackoverflow
Solution 1 - ShellPoomalairajView Answer on Stackoverflow
Solution 2 - ShellDorView Answer on Stackoverflow
Solution 3 - Shelluser405725View Answer on Stackoverflow
Solution 4 - ShellCiro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 5 - ShellmarcelogView Answer on Stackoverflow
Solution 6 - ShellWulfView Answer on Stackoverflow
Solution 7 - ShellGlenn John OgapongView Answer on Stackoverflow
Solution 8 - ShellMattView Answer on Stackoverflow
Solution 9 - ShelllukmacView Answer on Stackoverflow