[root@oel01db ~]# echo hello
hello
[root@oel01db ~]#
[root@oel01db ~]# echo $?
0
[root@oel01db ~]#
[root@oel01db ~]# echo hello | grep hi
[root@oel01db ~]#
[root@oel01db ~]# echo $?
1
[root@oel01db ~]#
$? always stores the exit status of the very last command executed in the foreground.In Linux, every command returns an exit status (stored in the $? variable) to tell the system how it went. For grep:
0(Success): A match was found.1(Failure to match): The command ran perfectly, but the pattern ("hi") was not found in the input ("hello").2(Error): There was a syntax error or the file doesn't exist.
## The Breakdown
cat non-existing-file: This command failed because the file doesn't exist. Its internal exit code was1.|(The Pipe): This passed the (empty) output ofcatover to the next command.tr , :: This command received nothing from the pipe, performed "nothing" successfully, and finished. Because it didn't encounter a system error, it exited with0.
Since tr was the last command in the pipeline, the shell updated $? to 0.
## How to see the "Real" failure
If you want to catch errors that happen earlier in the pipe, you have two main options:
Option 1: Use ${PIPESTATUS} (Bash/Zsh)
PIPESTATUS is a built-in array variable in Bash that stores the exit status (return codes) of every single command in the most recently executed foreground pipeline.
[root@oel01db ~]# cat non-existing-file | tr , :
cat: non-existing-file: No such file or directory
[root@oel01db ~]# echo "${PIPESTATUS[@]}"
1 0
1is the failure fromcat.0is the success fromtr.
Option 2: Use set -o pipefail
This is a safer way to write scripts. If you enable this, the entire pipeline will return a non-zero exit code if any command in the chain fails.
[root@oel01db ~]# set -o pipefail
[root@oel01db ~]# cat non-existing-file | tr , :
cat: non-existing-file: No such file or directory
[root@oel01db ~]# echo $?
1[root@oel01db ~]#
No comments:
Post a Comment