FUNDAMENTALS A Complete Guide for Beginners
In Bash, piping commands stand as a foundational concept. This allows chain commands for execution using the pipe “|” symbol facilitating seamless data flow between commands. Thus, working with pipelines (piped commands) with exit codes is a crucial part of effective error handling and process management based on the success or failure of commands. Therefore, this article comprehensively guides how to handle piped commands using Bash pipestatus. It discusses the use of exit status in a pipeline in general at first and subsequently dives deeply into “pipestatus” in Bash to handle exit codes of each command in a pipeline.
Exit Codes in Piped Commands in Bash
Piped commands generally connect a series of commands using the piping operator (|). When commands are piped, the output of one command serves as the input to the next command. In the case of Bash piped commands, the exit code status is typically the code of the last executed command in the pipeline. Here are 2 example commands to run in the terminal:
echo "hello world" | grep "hello" | wc -c
echo "hello world" | grep "multi" | wc -c
First, the above command prints the string “hello world” using the echo command. Then this string is piped to the grep command as input to find if it contains the pattern “hello”. After that, the final piping to the wc command counts the number of characters using the -c
option and displays the character count. Similarly, the 2nd pipeline locates the pattern “multi” and outputs accordingly.
Now, to check the exit code of the above pipeline, run the following command:
echo $?
Here, you can see the exit code of the entire pipeline is the exit code of the successful run of the wc -c
(last executed in the pipeline) command.
Additionally, in case of failure, the exit code of the entire pipeline is, still, the code of the last command executed. For clarification, run the following commands in the terminal:
LS | echo "hello"
ls | grep "multi"
Note: The $? variable (dollar question mark) is a special variable that holds the exit code of the last executed command. It is a specific shell variable reserved to find out if the command has been executed with success or not. Using the echo command within the syntax echo $? as above, it returns the exit code in the terminal.
What is “PIPESTATUS” in Bash?
PIPESTATUS is a Bash environment variable of array type that stores the exit status of all the individual commands in a pipeline. Generally, the exit code of piped commands is the code of the last executed command. However, if checking the exit codes of each command becomes necessary, the “PIPESTATUS” array is a useful option. It allows the users to access the exit codes for more robust error handling, debugging, and complex piped-based process management. For instance, after running the piped commands ls | grep “hello.txt”, the “PIPESTATUS” array will hold the 2 exit codes of the 2 commands ls and grep to denote the success or failure condition of the individual commands.
To access the “PIPESTATUS” array, use the length expression syntax ${PIPESTATUS[@]} or ${PIPESTATUS[*]} to expand all the elements of the Bash array PIPESTATUS. Finally, the “echo” command displays the elements of the array employing echo ${PIPESTATUS[@]}
or echo ${PIPESTATUS[*]}
. Thus, it displays the exit codes of each piped command.
“PIPESTATUS” to Find Exit Codes of Piped Commands
This section mentions the use of the PIPESTATUS array to find the exit codes in a pipeline. It discusses the terminal-based and Bash script-based examples with piped commands to show how PIPESTATUS gets the individual exit codes for error handling.
To start, open the terminal by pressing CTRL+ALT+T and run the piped commands mentioned below:
ls Bash_codes | grep "example" | wc -w
First, the above pipeline accesses the Bash_codes folder with the ls command and tries to find any item having the pattern “example” by piping the output of “ls” into the “grep” command as input. This is then piped into the wc command to get the word count of the items containing “example”. fa
Now, to access the exit codes of the above pipeline, execute this command:
echo ${PIPESTATUS[@]}
The expression echo ${PIPESTATUS[@]}
prints the exit codes of all the 3 commands of the executed pipeline in order. The codes 0, 0, and 0 signify that every pipeline step is successful.
Moreover, locating any error condition within the piped commands using the PIPESTATUS array is simple. To explore, run the following command which is slightly modified from the above example:
ls Bash_codes | GREP "example" | wc -w
So, as the grep command is mistakenly written as GREP, it will encounter an error condition and return a non-zero exit status (seen in the image). However, the other commands executed with exit code 0 denoting success. That’s how “PIPESTATUS” enables error detection and handling by concentrating on each process in pipelines.
PIPESTATUS with Single-Line Execution
Alternatively, you can execute piped commands and access the exit codes from the PIPESTATUS array expansion within a single line. To do so, just separate the commands with a semicolon (;). See the below example command:
ls Folder | grep "hello.txt"; echo ${PIPESTATUS[*]}
In addition, you can use the following syntax, to check the exit status of the piped command in the terminal in one line like the above:
ls Folder | grep "hello"; echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}
In the above, the method uses the syntax echo ${PIPESTATUS[idx] to access each element of the array (exit codes). Here, idx is the index number of the array elements (0-based).
Here, PIPESTATUS[0]
displays the exit code of the first command as the first array element & similarly PIPESTATUS[1]
for the second command as 2nd element.
Find Exit Codes in Bash Scripts Using “PIPESTATUS”
Using piped commands in Bash scripts is a common scenario. It facilitates the handling of a wide range of commands within scripts achieving automation. As a result, the observation of individual exit codes of pipelines within a script is a stark concern. So, this section will show how to use the PIPESTATUS array to find exit codes of piped commands in scripts. Let’s dive into the topic with an example below:
#!/bin/bash
# the pipeline to run
echo "hello world1 world2 world3" | grep "world" | wc -w
# assign PIPESTATUS array to codes array to store exit codes
codes=(${PIPESTATUS[@]})
# Access exit codes
echo "the 1st exit code: ${codes[0]}"
echo "the 2nd exit code: ${codes[1]}"
echo "the 3rd exit code: ${codes[2]}"
First, the above script first executes a pipeline of 3 commands. Then it assigns the PIPESTATUS array into another array named codes to store the exit codes. Finally, the expression echo ${codes[index]} executes 3 times to print the array elements (the exit codes of the pipeline here).
Note: you can use the code echo ${code[@]}
to print all the exit codes in the pipeline in a single line. Moreover, you can use the line of code echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
in the script to get exit codes of all the piped commands.
Caution 1: Properly Access the “PIPESTATUS” Array
The proper accessing method adoption to the “PIPESTATUS” array helps avoid potentially unwanted outcomes. First, run the following pipeline in the terminal:
cat games.txt | wc -w
Here, you see that accessing the first exit code using echo $PIPESTATUS[0]}
outputs 0 successfully. However, accessing the 2nd exit code gives no output.
Reason: The reason is that the echo ${PIPESTATUS[0]}
is a pipeline too of a single “echo” command. So, “PIPESTATUS” is populated with its exit code before the execution of echo ${PIPESTATUS[1]}
. As the previous pipeline contains only one command, PIPESTATUS[1] is rendered empty.
Solution: The solution is to access the “PIPESTATUS” array with effective methods so that it’s not overwritten. In case of terminal-based execution, expand the “PIPESTATUS” array using ${PIPESTATUS[@]} or ${PIPESTATUS[*]} to get the exit codes. This is possible either after pipeline execution or in a single line separated by semicolons. Moreover, use the code echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} … ${PIPESTATUS[N-1]}; where “N” is the number of the last command.
Accessing “PIPESTATUS” Properly within Bash Scripts
Similarly, the above is true for Bash scripts. Look at the example below for a better understanding:
#!/bin/bash
# pipeline
cat games.txt | wc -w
# access exit codes from PIPESTATUS
echo "the 1st exit code: ${PIPESTATUS[0]}"
echo "the 2nd exit code: ${PIPESTATUS[1]}"
Solution: In scripts, you can refer to using the array expanding methods and access the elements like the following example after the immediate execution of the pipeline:
#!/bin/bash
#the pipeline
cat games.txt | wc -w
# approach: storing PIPESTATUS array to another Bash array
piped_codes=(${PIPESTATUS[@]})
# print the codes:
echo "the exit codes: ${piped_codes[@]}"
Note: In addition, you can use the syntax echo ${PIPESTATUS[0]} ${PIPESTATUS[1]
} in the same manner as above to get the piped exit codes seamlessly. Moreover, you can directly use the array expansion syntax echo ${PIPESTATUS[@]
after pipeline execution to achieve the same result in tackling the issue.
Caution 2: Access “PIPESTATUS” after Immediate Pipeline Execution
Another important thing to consider is to access the PIPESTATUS array immediately after the execution of the piped commands. Otherwise, its contents (the exit codes) can easily be overwritten. This is because the “PIPESTATUS” variable is volatile which resets as soon as any other command or pipeline executes.
Look at the following image that shows the running of the date command after executing a pipeline:
It is visible that accessing the “PIPESTATUS” array returns only one value of 0. However, it should have returned 2 values as the pipeline contains 2 commands.
Solution: Make use of the “PIPESTATUS” array after the immediate execution of the piped commands. Now, look at the image below for clarification:
The image states that the “PIPESTATUS” array is accessed immediately after a pipeline execution. Thus, it seamlessly returns the correct exit codes for each command and avoids unwanted overwriting of its elements.
Conclusion
This article mentions an in-depth analysis of the PIPESTATUS array in Bash. It first discusses exit codes in piped commands. Then it evolves to focus on the ins and outs of “PIPESTATUS” to concentrate on finding the exit codes of piped commands on an individual basis. Additionally, it mentions 2 precautionary measures to consider when working with “PIPESTATUS” in Bash.
People Also Ask
What is the difference between “pipefail” and “PIPESTATUS” in Bash?
The difference between “pipefail” and “PIPESTATUS” in Bash is that “pipefail” is a Bash option that is used with the set command within the syntax set -o pipefail
. When it is set, the pipefail option makes the pipeline return a non-zero exit code status of the last executed command that fails with that code in the pipeline. For example, the pipefail option makes the exit code to 1 if you run the pipeline false | true. This is because the false command returns exit 0 due to failure.
On the other hand, the “PIPESTATUS” is a Bash array variable that stores the exit codes of each command in a pipeline. This allows one to check all the exit codes of piped commands for more flexible error handling with minute details of each step.
What does the “PIPESTATUS” variable do in Bash?
The “PIPESTATUS” is a built-in Bash variable of array type that successfully stores all the exit codes of the commands used in a pipeline. So, it allows the users to examine the exit status of each command for robust handling of errors within piped commands. For example, if you wish to check each exit code after running the pipeline ls | grep "hello.txt"
, you can immediately access the array using echo ${PIPESTATUS[*]}
to check its elements (exit codes in this case).
How can I get the exit codes of all the commands in a pipeline?
To get the exit codes of all the commands in a pipeline, run the command echo ${PIPESTATUS[*]}
immediately after executing the piped commands. This will display all the exit codes in the terminal by expanding the PIPESTATUS array variable. For instance, after running the pipeline echo "hello" | wc -w
, you can execute the code echo ${PIPESTATUS[*]}. The output will be 0 0. This marks that each command in the pipeline has been executed successfully.
Why is it useful to use “PIPESTATUS” in Bash?
It is useful to use “PIPESTATUS” in Bash because it provides valuable insights regarding the commands used in a pipeline. For example, it allows for a successful checking of the exit codes of all the individual piped commands. This is handy in error detection and debugging for a successful pipeline execution. It also allows for the development of robust scripts in complex pipeline scenarios.
Can I print the all exit codes of the piped commands in the terminal?
Yes, you can. Use the array expression ${PIPESTATUS[@}] with the echo command just after executing the piped commands in the terminal. The expression “${PIPESTATUS[@]}” expands the array of elements and the “echo” command displays them on the screen. The full syntax is echo ${PIPESTATUS[@]}
.
What is the exit code of a pipeline in Bash?
The exit code of a pipeline is generally the code of the last executed command. If the last command in the pipeline executes successfully, it exits with the code 0 and the exit code status of the entire pipeline becomes 0. This is true even if earlier commands in the pipeline fail. On the other hand, if the command encounters error conditions, it returns a non-zero exit code, and the whole pipeline exits with that non-zero exit code.
What is PIPESTATUS[0] in Bash?
The PIPESTATUS[0]
is an expression that denotes the storing of the exit code of the 1st command in the pipeline by the Bash “PIPESTATUS” array. For example, suppose, you have run the piped commands echo “hello” | grep "hello"
in the terminal. After running the command echo ${PIPESTATUS[0]}
, you will get 0 as output in the terminal. This signifies that the echo "hello"
command executes successfully returning the exit code 0. Here, the expression PIPESTATUS[0] holds the exit code of the first command (echo “hello”).
Related Articles
- 4 Methods to Exit Bash Scripts on Error with Message
- Usage of “exit” Command in Bash [Explained]
- How to Set Exit Codes in Bash? [An Easy Guide]
- How to Set & Use Pipefail in Bash [Explained Guide]
- [4 Methods] How to Check Exit Code in Bash?
- [Explained] What Are “exit 0” and “exit 1” in Bash?
<< Go Back to Exit Codes in Bash | Bash Process and Signal Handling | Bash Scripting Tutorial