Skip errors
How to perform a command without causing the script to abort, either by not executing the command or forcing a success result.
The assumption is this set as start of the script such that any errors would cause the script to abort.
set -e
Related
- Status check cheatsheet
Default
Assume that CMD
references a failing command such as running copy, move or remove on a file or folder that is not valid to operate on. e.g. rm foo.txt
when foo.txt
does not exist.
CMD
Run echo $?
after and you’ll see 1
or another error status code.
You’ll also have any error messages logged on stderr.
Continue without aborting
OR and true to force success
If a step is optional or will only be needed sometimes (like deleting a temporary file which won’t exist on the very first run).
CMD || true
If you run echo $?
you’ll see 0
for success, as it uses the exit code for the entire line above it (which will come from the last executed piece).
This works for variables and subshells too.
Example - here using npm outdated
which gives an error if there are packages to update, and capturing the output in a variable without aborting.
$ OUTDATED=$(npm outdated)
$ echo $?
1
$ OUTDATED=$(npm outdated) || true
$ echo $?
0
Note, you could use ;
instead, but then the second bit will always run, which is unnecessary.
If statement
Here we check if packages are up to date (code 0
) or outdated (code 1
). Also output is silenced.
if npm outdated > /dev/null; then
echo 'Nothing to update'
exit 0
fi
echo 'Upgrading'
npm update
Here capturing the output. And assuming set -e
not set, so that a command can fail and its exit status can be used.
OUTDATED=$(npm outdated)
if [[ "$?" -eq 0 ]] > /dev/null; then
echo 'Nothing to update'
exit 0
fi
echo 'Outdated packages:'
echo "$OUTDATED"
echo
echo 'Upgrading'
npm update
Hide error output
Silence stderr. Keep stdout.
CMD 2> /dev/null
See Redirection cheatsheet.
Continue without aborting and fail silently
Combine the sections above:
CMD 2> /dev/null || true
Run conditionally
You could add a targeted if
statement to check that a file or folder is already there or not, rather than using a catchall as in the previous sections.
You could check if file exists and is readable and is executable. Or just pick one of those tests.
# Optional command
if [[ -f foo.txt ]]; then
rm foo.txt
fi
# More commands
Here is a directory check in one line.
# Optional command.
[[ -d foo ]] && rm -rf foo
# More commands
Maybe you want to check it is empty.
[[ -z foo.txt ]]
There could be multiple reasons for the command to fail and you’d have to catch them all.
Here is a DRY approach (replace source
with echo
to just print).
test -f ~/.git-completion.sh && source $_
That uses the last argument of previous command on the same line and uses it in place of $_
.
Now this only works with the test CONDITION
syntax. Using [[ CONDITION ]]
ends up using ]]
instead of the path.
Compare with this (which works only works in interactive mode I think):
test -f ~/.git-completion.sh
source !$
Also in ZSH, you have to press enter a second time at the end to confirm the substitution.
Set error flag
You could also reverse the error flag so that errors are not fatal. This can be especially useful for ignoring errors on a series of lines.
set -e
# Do stuff.
set +e
# Do stuff that can fail.
set -e
# Do more stuff.