Consider the following function
function current_dir {
set -e
git foobar
echo "I will not print this, because git foobar returned a non-zero exit code"
}
Now, when I source the function and try to call it in my shell, it exits not only the function, but also the shell itself.
How can this be avoided?
If you don't need the function to execute in the current shell (e.g., it isn't setting any parameter values that need to be visible to the caller), you can make the body of the function a subshell, not a command group:
current_dir () (
set -e
git foobar
echo "I will not print this, because git foobar returned a non-zero exit code"
)
As far as I know, set -e
will do exactly what you see: exiting the shell completely as soon as a command exits with a non-zero status.
You can try to reformulate your function with trap
or using &&
between the commands:
function current_dir {
git foobar && echo "I will not print this, because git foobar returned a non-zero exit code"
}
or (better readability):
function current_dir {
trap 'trap - ERR; return' ERR
git foobar
...other commands...
echo "I will not print this, because a command returned a non-zero exit code"
}
If you really need set -e
for some reason, you can temporary disable it with set +e
and reenable it again after your critical section.
"set -e" is used to exit immediatly when a command (a pipeline or a sub-shell command, etc.) exits with a non-zero status.
By default, BASH ignores errors and continues to interpret your script. This can cause a very bad surprise, an example:
if ! lss myLock
then touch myLock; echo "No lock, I can do the job"; rm -f myLock
fi
The result of this script is:
bash: lss : commande introuvable
No lock, I can do the job
As you can see, BASH makes no difference between a command not found and a command which failed.
"-e" is frequently used to make sure the Shell interpretor will stop immediatly after an error (so we have to think about all errors...) This help to prevent a very bad issue when we performed a mistake in the script (think about a rm -rf "$v"/* when you forgot to set v ;-)). For this purpose we pass "-e" option in the shebang. Obviously, it's not designed for interactive use, and I don't imagine a good usage of "set -e", nor of "set +e" (but to test).
To answer to your initial question. You can avoid the termination of your shell by applying one of the following solution:
Use if statement
function myF1() {
if git foobar; then
echo "I will not print this, because git foobar returned a non-zero exit code"
fi
}
Use the control operator &&
function myF2() {
git foobar && \
echo "I will not print this, because git foobar returned a non-zero exit code"
}
Open a subshell
function myF4() {(
set -e
git foobar
echo "I will not print this, because git foobar returned a non-zero exit code"
)}
In this case, "set -e" will exit immediatly of the sub-shell, but it will not terminate the caller :-)
Use a trap is not a good idea here as it would cause a side-effect on the caller (the trap is defined globally). Obviously we can combine trap and sub-shell, but it's not useful in your case.