What does
echo $?
mean in shell programming?
What does
echo $?
mean in shell programming?
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.
cmd; if [ $? -eq 0 ]; then
should be refactored to if cmd; then
. The very purpose of if
(and the other flow control statements in the shell) is to run a command and examine its exit status. –
Replicate if cmd;
may not be very readable is some conditions especially when cmd refers to another script. –
Molybdate [ 1 ]
and [ 0 ]
are both true; [
without an operator checks if the argument is a non-empty string. –
Replicate externalscript; if [ $? -eq 0 ]
be more readable than if externalscript
? –
Replicate vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;
. If I had to put that in a single line if [ ... ]
it would be terribly unreadable. I plan to store the output of that line to a variable so I can just say if [ $drupal_installed -eq 0 ]
later. –
Hamitic “$?”
to see if a command succeeded or not, an anti-pattern? –
Replicate if cmd
, if I need to act according to more than two cases, I need to check against, for example, 0 and 1 and 2. –
Theodolite 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., ) .
It has the last status code (exit value) of a command.
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:
* https://mcmap.net/q/13911/-why-does-wait-set-status-to-255-instead-of-the-1-exit-status-of-the-forked-process
**/
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.
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.
Outputs the result of the last executed unix command
0 implies true
1 implies false
© 2022 - 2024 — McMap. All rights reserved.
$?VARIABLE_NAME
has a different meaning, for checking if a variable is set. – Loiseloiter