In your code with set -e
(short for set -o errexit
) unhandled command failures cause the shell to exit.
pidof
returns with a failure exit status when no matching process is found, but you do handle that failure. pidof
is used as part of a and-or list, so its failure does not trigger errexit
.
However because you used an and-or list where you should have used a if
construct, the pidof && othercommand
itself exits with a non-zero exit status and because that and-or list is the last thing run in the checkIfRunning
function, the checkIfRunning
function itself will also return with a failure exit status.
And that failure is not handled, so errexit
is triggered. errexit
is triggered not because pidof
fails but because checkIfRunning
failed.
Here, you should have written:
checkIfRunning() {
if pidof -o %PPID -x -- "$0" >/dev/null; then
echo >&2 'Already running!'
exit 1
fi
}
The exit status of a if
construct is that of the last command run in the then
or else
part or 0
if none was run, not the exit status of the condition part.
Generally, replacing if
constructs with and-or lists is wrong. Besides the problem of the overall exit status, if echo
fails in your pidof && echo && exit 1
, the script doesn't exit.
I'd argue that as soon as you use functions or anything other than the simplest script, errexit
should be avoided and proper error handling be done.
See the corresponding section about set -euo pipefail
in the bash wiki (short for set -o errexit -o nounset -o pipefail
) or this FAQ entry.
Regarding your (now deleted) answer which tried to address the problem with:
checkIfRunning() {
set +e # <---
pidof -o %PPID -x $0 >/dev/null \
&& echo "running!" && exit 1
set -e # <---
}
The only reason it works is because set -e
happens to exit with a success status, so checkIfRunning
does as well, the set +e
is irrelevant and not needed, set -e
could have been replaced with true
or return 0
.
./myscript.sh
. Are you implying the above should work and the problem is elsewhere? – lonix Jul 16 '22 at 07:29$0
inside a function expands to the name of the function. Something to bear in mind if you intend to switch to another shell in the future. HavingSCRIPTNAME=$0
at the start of the script and refer to that instead would make your script more portable. – Stéphane Chazelas Jul 16 '22 at 08:58function f { ...;}
syntax. – Stéphane Chazelas Jul 16 '22 at 09:04man set
says that The-e
setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word (...) or any command of an AND-OR list other than the last. -- I read this as: "set -e
will not react to anything in a&&
-chain except the last command", which in this case simply exits 1 (successfully). – pzkpfw Jul 16 '22 at 09:56set
command. It seems on your systemset
man page documents theset
special builtin of some POSIX-like shell, or maybe it's actually the POSIX specification of the specialset
sh
builtin. Here, the OP would want to look at the documentation of their own shell. Likeinfo bash set
forbash
orinfo zsh errexit
forzsh
– Stéphane Chazelas Jul 16 '22 at 14:58