Consider the commands
eval false || echo ok
echo also ok
Ordinarily, we'd expect this to execute the false
utility and, since the exit status is non-zero, to then execute echo ok
and echo also ok
.
In all the POSIX-like shells I use (ksh93
, zsh
, bash
, dash
, OpenBSD ksh
, and yash
), this is what happens, but things get interesting if we enable set -e
.
If set -e
is in effect, OpenBSD's sh
and ksh
shells (both derived from pdksh
) will terminate the script when executing the eval
. No other shell does that.
POSIX says that an error in a special built-in utility (such as eval
) should cause the non-interactive shell to terminate. I'm not entirely sure whether executing false
constitutes "an error" (if it was, it would be independent of set -e
being active).
The way to work around this seems to be to put the eval
in a sub shell,
( eval false ) || echo ok
echo also ok
The question is whether I'm expected to have to do that in a POSIX-ly correct shell script, or whether it's a bug in OpenBSD's shell? Also, what is meant by "error" in the POSIX text linked to above?
Extra bit of info: The OpenBSD shells will execute the echo ok
both with and without set -e
in the command
eval ! true || echo ok
My original code looked like
set -e
if eval "$string"; then
echo ok
else
echo not ok
fi
which would not output not ok
with string=false
using the OpenBSD shells (it would terminate), and I wasn't sure it was by design, by mistake or by misunderstanding, or something else.
Best Answer
That no other shell needs such workaround is an strong indication that it is a bug in OpenBSD ksh. In fact, ksh93 doesn't show such issue.
That there is a
||
in the command line must avoid the shell exit caused by an return code of 1 on the left side of it.The error of an special built-in shall cause the exit of a non interactive shell acording to POSIX but that is not always true. Trying to
continue
out of a loop is an error, andcontinue
is a builtin. But most shells do not exit on:A builtin that emits a clear error but doesn't exit.
So, the exit on
false
is generated by theset -e
condition not by the builtin characteristic of the command (eval
in this case).The exact conditions on which
set -e
shall exit are quite more fuzzy in POSIX.