Exit Code of Last Command in Bash

Bash get exit code of last command

Every command we run successfully or unsuccessfully in Bash leaves a particular code behind, which we call an exit code or exit status. We use this code to analyze the last command in Bash.

Using $? Variable

Use shell variable, $?, to get the exit code of the last-run command in Bash.

We ran the date command to get the current date and time, which ran successfully without prompting errors. Then, we used the shell variable represented by $? to grab the exit code of the date command and stored it in the exit_code variable.

Finally, we used an echo command to print the value of the exit_code variable. Note that the variables are prefixed with $ to capture their values. It does not matter whether the command ran successfully; the value of the $? variable would always be a number.

Usually, the exit code of the successfully executed command is 0, and any non-zero number ranging from 1 to 255 denotes an error or some particular condition that occurred while running the command. For example, the 127 exit code means command not found; you can learn more about exit codes here.

As we have limited numbers, every non-zero value will be unique to the script or program. For example, the meaning of exit code 1 differs for ls and grep commands. See the following.

Scroll downwards and look for the Exit status as shown below.

Scroll downwards and search for the Exit status as given below.

It is always recommended to use the man command to check the exit status of a particular command you will use.

If your user is a technical person, then it is OK to display the exit codes to inform whether the command was executed successfully or not. But what if you are working for a non-tech person? In that case, we have to communicate a message in his understandable language. So let’s see how to do it.

Use $? Variable with if-else Statement

Use shell variable ($?) with if-else statement to show the customized message if the command ran successfully/unsuccessfully in Bash.

This approach is best suited for a non-tech user to know whether the command succeeded or not. In the above example, as soon as we ran the date command, the exit code was stored in the $? variable.

We used the $? with the -eq operator in the if statement to determine if the value of the shell variable ($?) equals 0. If it is, display the The 'date' Command Succeeded. message using the echo command; otherwise, jump to the else section to print the The 'date' Command Failed. message on the Bash console.

Use $? with && and || Operators

Use the shell variable ($?) with && and || operators to display a custom message based on the command. It is the compact form of if-else. See the following example.

Here, the command after the && operator would run if the previous command was executed successfully (exit status was 0), whereas the command after the || operator would run if the last command failed (non-zero exit status). The date command succeeded in the above example, so the echo after && was executed.

Using PIPESTATUS Array

If you are working with piped commands, use the PIPESTATUS array to capture the exit codes of all commands.

In the above example, we have three commands that we piped together. First, we executed the echo command and forwarded its output ("Hello, world!") to the grep, our second command. Here, the grep searched and found the world pattern and piped it to the sed command. The sed command replaced the world with Java2Blog.

Next, we used an echo command with bash array (${PIPESTATUS[@]}) to print exit statuses of all commands in the most recently executed pipeline. The value at index 0 represented the exit code for the first command in the pipeline, the value at index 1 denoted the value of the second command in the pipeline and so on.

In the ${PIPESTATUS[@]} bash array, every element represents an exit code for a particular command within the pipeline. Therefore, as all commands were executed successfully so, we got all zeros (0 0 0), as you can see in the above output.

Let’s see another example where at least one command fails.

Here, we got 1 for the grep command, which searched for the planet that did not exist in the received input; here, the input for the grep command was the output of the echo "Hello, world!" command.

The ${PIPESTATUS[@]} bash array contains the exit codes for the most recently executed pipeline. In ${PIPESTATUS[@]}, the ${PIPESTATUS} refers to the PIPESTATUS array, which is an array to capture the exit codes of the commands within the pipeline. At the same time, the [@] notation expands the array into the list of its items.

If you are not interested in all commands’ exit codes, then you can access the exit code for a particular command using index notation as follows.

You must know your command’s number (n) in the pipeline for the above approach. Note that the index in the index notation would be n-1 because arrays always start with 0.

Why am I getting the exit code for the last-run command regardless of whether the exit code was zero or non-zero, while I am only interested in getting the exit code for the last-run command causing an error (with a non-zero exit code)? For that, we must use the trap command. So let’s learn it below.

Using trap Command with ERR Signal

Use the trap command with the ERR signal to get the exit code of the last-run command, which caused an error in Bash.

First, we used the trap command to set up a trap for the ERR signal, which was triggered when any command within the script failed and exited with a non-zero code. Then, the code written in single quotes ('exit_code=$?') was executed when the ERR signal was caught. Here, the exit_code=$? line assigned the exit code of the last-run command to the exit_code variable; you can refer to [Using $? Variable](add the link here) section to learn about this line in detail.

Why did we set up this trap? We did it to capture the exit code for the last executed command after the trap statement. The echo command was used to display the exit status of the last run command.

The exit_code variable will only hold the command’s exit code executed immediately after the trap command/statement. If you have additional commands to run, their exit code will not be captured in this variable.

Let’s see another example which does not have any errors.

We could not see the exit code in the above output because the ERR signal was not triggered. As the ERR signal was not activated, the code enclosed within single quotes ('exit_code=$?') would not run. Why the ERR was not triggered because the command within the trap block (date command) was executed successfully.

Now, think of a situation where you have some commands running in the background for which you want to grab the exit code. So, let’s explore how we can do it.

Using wait Command

Use the wait command to get the exit code of the last command running in the background and completed.

We used the date command with the & sign to run it in the background. Executing commands in the background allowed the script to continue running while the date command ran concurrently.

Here, the wait command waited for the background process, identified by $!, representing the process ID (PID) of the last-run background command (date in this case). Here, the wait command suspended the execution of the script until the background process finished.

Once finished, we captured the exit code using the shell variable ($?) and stored it in the exit_code variable, which was further used with the echo command to display on the Bash console.

You can observe the above output; first, we see the process id running in the background. Then, we see the date command’s output and a message saying the command was done. Lastly, we saw the exit code of the date command running in the background.

Let’s modify the code and write an incorrect command; we are using the dates command in the following example.

The above code worked fine. We waited for the dates command to finish, grabbed its exit code and displayed it. As the dates command was incorrect, we got a 127 exit code indicating a command not found error.

Remove the wait $! line from the code as follows and re-run it to see the importance of wait $!.

This time, we got exit code 0, but we also had an error stating command not found, which means the command exit_code=$? was executed before the dates & finished. This is why we use wait $! to let the command complete and then grab the exit code.

Until now, we executed all the commands on the Bash terminal. What if we are instructed to write commands in the script and exit the script immediately as soon as any command causes a non-zero exit code? See the following section.

Using set Command

Use the set command with the -e option to exit the script immediately if any command within the script returns the non-zero exit code in Bash. We write the following script in the test.sh file.

We used the set command enabling the -e option, which would exit the script immediately if any of the commands returned a non-zero exit code. For example, in the above script, the first echo command successfully printed Welcome to Java2Blog!, but the dates command returned a non-zero exit code (127). That’s the reason the last three statements were not executed.

Let’s remove the set -e command from the script and observe the output below.

See, the first echo command succeeded and printed Welcome to Java2Blog! on the Bash console. Then, we got an error displayed on the console saying the command was not found, which was caused by the dates command. At this step, the script didn’t stop but continued the execution and printed the exit code (127) and the Let's learn together message.

The set -e assists us in terminating the script if any of the commands from the script causes an error (returns the non-zero exit code).

So, we explored various approaches to capture the exit code of the last run command. It’s up to you for which command you want to grab the exit code. Is it the last executed command, the command running in the background, or any from the script? You can go ahead with the solution as per your use case.

That’s all about how to get exit code of last command in Bash.

Was this post helpful?

Leave a Reply

Your email address will not be published. Required fields are marked *