Git is starting to optionally run its testsuite under `set -e` and so
I've been testing various shells in that configuration. I noticed that
mksh and lksh appear to mishandle `set -e` in some circumstances.
For instance, with the script below, mksh prints `not ok 1`, whereas
dash, bash, zsh, and posh print `ok 1`.
POSIX[0] states the following about `set -e`:
When this option is on, when any command fails (for any of the
reasons listed in 2.8.1 Consequences of Shell Errors or by returning
an exit status greater than zero), the shell immediately shall exit,
as if by executing the exit special built-in utility with no
arguments, with the following exceptions:
[...]
The -e setting shall be ignored when executing the compound list
following the while, until, if, or elif reserved word, a pipeline
beginning with the ! reserved word, or any command of an AND-OR list
other than the last.
It appears mksh is mishandling this case because the `check_command`
function is exiting unsuccessfully (due to the `test` not matching) even
though the command if being run under an `if` in `test_run`, which
should disable existing on `set -e`.
It would be nice if this could be fixed, since I often recommend mksh as
a portable shell that people can use to run the Git testsuite (which
requires POSIX conformance as well as `local`; roughly a subset of
Debian `/bin/sh` requirements).
Output:
----
% dash test.sh
ok 1
1..2
% bash test.sh
ok 1
1..2
% zsh test.sh
ok 1
1..2
% posh test.sh
ok 1
1..2
% mksh test.sh
not ok 1
1..2
% lksh test.sh
not ok 1
1..2
----
Script test.sh:
----
#!/bin/sh
set -e
TESTNUM=1
test_run_ () {
eval "$1"
}
test_run () {
local body="$1"
if test_run_ "$body"
then
echo "ok $TESTNUM"
else
echo "not ok $TESTNUM"
fi
TESTNUM=$((TESTNUM + 1))
}
test_done () {
echo "1..$TESTNUM"
}
check_command () {
test "$1" = barbaz
case "$1" in
foobar)
;;
barbaz)
;;
esac
}
test_run '
check_command foobar
'
test_done
----
[0] https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_26