You might think that exit 1 will do a hard stop on your script.
And while it will be a hard stop on the particular process that you are running in, that does not mean it will halt your script.
An example to illustrate this is as follows:
foo() {
echo "foo: I am foo and I am exiting!!! [\$\$=$$/$BASHPID]"
exit 1
}
export -f foo
main() {
echo "MAIN: [\$\$=$$/$BASHPID]"
local foo_result
foo_result="$(foo)"
echo "MAIN: And I don't care that you exited I am going to keep going"
echo "MAIN: You said: [${foo_result:?}], but I am 'main' and had other plans."
return 0
}
main "${@}" || exit 1The output is as follows, where exit 1 did not stop main from continuing.
MAIN: [$$=3006467/3006467]
MAIN: And I don't care that you exited I am going to keep going
MAIN: You said: [foo: I am foo and I am exiting!!! [$$=3006467/3006472]], but I am 'main' and had other plans.The reason is that $() spawned a new process (see parenthesis-spawn-a-subshell). You can see this by the different BASHPID that correctly identified the process id. So exit 1 only exited 3006472 PID and not 3006467.
In a subshell created by $(), exit 1 behaves similarly to return 1 in that it doesn’t propagate beyond that subshell.
Example how main should have collaborated, if we are using exit 1/return 1
foo() {
echo "foo: I am foo and I am exiting!!! [\$\$=$$/$BASHPID]"
exit 1
}
export -f foo
main() {
echo "MAIN: [\$\$=$$/$BASHPID]"
local foo_result
foo_result="$(foo)" || {
echo "MAIN: I will respect your wishes to exit..."
exit 1
}
echo "Continuing... with happy foo result: ${foo_result:?}"
return 0
}
main "${@}" || exit 1PS
⚠️ One might think 'set -e' would save us in the first example but it does not ⚠️
set -e does not save us
If we set -e (See set-e).
We could expect the first example to halt, due to non zero code returned by $(foo)
set -e
foo() {
echo "foo: I am foo and I am exiting!!! [\$\$=$$/$BASHPID]"
exit 1
}
export -f foo
main() {
echo "MAIN: [\$\$=$$/$BASHPID]"
local foo_result
foo_result="$(foo)"
echo "MAIN: And I don't care that you exited I am going to keep going"
echo "MAIN: You said: [${foo_result:?}], but I am 'main' and had other plans."
return 0
}
main "${@}" || exit 1But the output will be still the same
MAIN: [$$=3012359/3012359]
MAIN: And I don't care that you exited I am going to keep going
MAIN: You said: [foo: I am foo and I am exiting!!! [$$=3012359/3012361]], but I am 'main' and had other plans.The reason for that is the following line
main "${@}" || exit 1And this behavior of set -e: having-success-or-error-path-prevents-set-e-from-triggering