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?
Often when writing Bash scripts, you will need to terminate the script when a certain condition is met or to take action based on the exit code of a command.
bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc.
One of the many known methods to exit a bash script while writing is the simple shortcut key, i.e., “Ctrl+X”. While at run time, you can exit the code using “Ctrl+Z”.
The -r tests if the file exists and if you have read permission on the file. Bash scripting tutorial - if statement. The meaning of -r depends on what program/command it is given as an argument for. In this case it is for [ , and means to check whether the file named by the next argument is readable.
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:
function myF1() {
if git foobar; then
echo "I will not print this, because git foobar returned a non-zero exit code"
fi
}
function myF2() {
git foobar && \
echo "I will not print this, because git foobar returned a non-zero exit code"
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With