I am using following options
set -o pipefail
set -e
In bash script to stop execution on error. I have ~100 lines of script executing and I don't want to check return code of every line in the script.
But for one particular command, I want to ignore the error. How can I do that?
The solution:
particular_script || true
Example:
$ cat /tmp/1.sh
particular_script()
{
false
}
set -e
echo one
particular_script || true
echo two
particular_script
echo three
$ bash /tmp/1.sh
one
two
three
will be never printed.
Also, I want to add that when pipefail
is on, it is enough for shell to think that the entire pipe has non-zero exit code when one of commands in the pipe has non-zero exit code (with pipefail
off it must the last one).
$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0
Just add || true
after the command where you want to ignore the error.
set -e
and trying to capture an error message: e.g.set -e; TEST=$(foo 2>&1 || true); echo $TEST
set -e
, redirect the bash command not found from stderr to $TEST
. How does this preserve the response code?
set -e; TEST=$(foo 2>&1) || printf "ERROR $?: $TEST\n"
Don't stop and also save exit status
Just in case if you want your script not to stop if a particular command fails and you also want to save error code of failed command:
set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
command
was successful and there is need to run what's after ||
. read it as: if command
fails, do EXIT_CODE=$?
. You probably could just do command || echo "$?"
or use "trap" for more verbose debugging. See this -> stackoverflow.com/a/6110446/10737630
More concisely:
! particular_script
From the POSIX specification regarding set -e
(emphasis mine):
When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit status value >0, and is not part of the compound list following a while, until, or if keyword, and is not a part of an AND or OR list, and is not a pipeline preceded by the ! reserved word, then the shell shall immediately exit.
-e
.
!
will prevent the shell from exiting no matter what. This script displays the message Still alive!
when I run it, indicating that the script ran to completion. Are you seeing different behavior?
if
clause and solved the problem.
particular_script
, but if particular script
is a function I do not want to ignore the return values of the statements inside the functions. The ||
solutions will ignore all return codes inside the function body of particular_script
, which is often not what you want (stackoverflow.com/a/37191242/985292).
||
does not work in dash, this does. thx!
Instead of "returning true", you can also use the "noop" or null utility (as referred in the POSIX specs) :
and just "do nothing". You'll save a few letters. :)
#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
alias null=:
and you can use null
in place of :
, if you find it clearer.
If you want to prevent your script failing and collect the return code:
command () {
return 1 # or 0 for success
}
set -e
command && returncode=$? || returncode=$?
echo $returncode
returncode
is collected no matter whether command succeeds or fails.
Thanks for the simple solution here from above:
<particular_script/command> || true
The following construction could be used for additional actions/troubleshooting of script steps and additional flow control options:
if <particular_script/command>
then
echo "<particular_script/command> is fine!"
else
echo "<particular_script/command> failed!"
#exit 1
fi
We can brake the further actions and exit 1
if required.
No solutions worked for me from here, so I found another one:
set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e
You can turn off failing on errors by set +e
this will now ignore all errors after that line. Once you are done, and you want the script to fail again on any error, you can use set -e
.
After applying set +e
the find
does not fail the whole script anymore, when files are not found. At the same time, error messages from find
are still printed, but the whole script continues to execute. So it is easy to debug if that causes the problem.
This is useful for CI & CD.
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status
Example of using this to create a log file
log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
if [ "$exit_status" = 0 ]
then
event="$output"
log_event
else
event="ERROR $output"
log_event
fi
I have been using the snippet below when working with CLI tools and I want to know if some resource exist or not, but I don't care about the output.
if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
echo "none exist actually exist!"
fi
if [ -r not_exist ]
I kind of like this solution :
: `particular_script`
The command/script between the back ticks is executed and its output is fed to the command ":" (which is the equivalent of "true")
$ false
$ echo $?
1
$ : `false`
$ echo $?
0
edit: Fixed ugly typo
while || true
is preferred one, but you can also do
var=$(echo $(exit 1)) # it shouldn't fail
Success story sharing
-e
attribute is set "if the command that fails is part of the command list immediately following awhile
oruntil
keyword, part of the test in anif
statement, part of any command executed in a&&
or||
list except the command following the final&&
or||
, any command in a pipeline but the last, or if the command's return status is being inverted with!
."(ldd $2/bin/* || true) | grep "not found" | wc -l
script is terminating after this line when ldd return failure(ldd $2/bin/* || true) | grep "not found" | wc -l || true
set -o pipefail
. whengrep
finds nothing, it returns non-zero exit code and it is enough for shell to think that the entire pipe has non-zero exit code.