327

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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
David Mulder
  • 7,595
  • 11
  • 45
  • 61
  • 101
    A good google search turns out to be "bash dollar question mark" – frankc Jul 26 '11 at 19:03
  • 13
    SymbolHound works well for searches involving special characters. Example: http://symbolhound.com/?q=%24%3F – Anssssss May 07 '13 at 17:54
  • 1
    `info bash` also works, but unfortunately you can't just search for "$?", since the documentation omits the `$`. Go to the "Special Parameters" section (3.4.2 as of version 4.2) or search for backtick-`\$'` (you have to escape the `?` because the search term is a regular expression). (I'm sure there's a way to put a literal backtick in a comment.) – Keith Thompson Aug 04 '13 at 20:59
  • 26
    That moment when googling "bash dollar question mark" brings this SO Question as first result. Don't blame us. – Dumoko Nov 10 '14 at 08:18
  • 1
    @KeithThompson You probably know this by now, but you can escape it with `\\` (so you end up writing `\\\`` to get the backtick) (and `\\\\\\\`` to get what I just wrote) – Nic Jan 08 '16 at 19:23

9 Answers9

339

$? 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.

Poomalairaj
  • 4,888
  • 3
  • 23
  • 27
52

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

Dor
  • 7,344
  • 4
  • 32
  • 45
22

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

Community
  • 1
  • 1
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
22

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.

  • For a moment, I thought `rv:` was some sort of old style options list, but it turns out just to be text which is echoed. – Joe Jul 15 '15 at 20:24
12

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

marcelog
  • 7,062
  • 1
  • 33
  • 46
6

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

Wulf
  • 3,878
  • 2
  • 22
  • 36
5

$? 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

Achrome
  • 7,773
  • 14
  • 36
  • 45
3

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.

Shubham
  • 2,847
  • 4
  • 24
  • 37
lukmac
  • 4,617
  • 8
  • 33
  • 34
3

The exit code of the last command ran.

Matt
  • 2,790
  • 6
  • 24
  • 34