source | all docs for version 0.8.pre10 | all versions | oilshell.org
Warning: Work in progress! Leave feedback on Zulip or Github if you'd like this doc to be updated.
Unix shell experts are divided on what the best way to handle errors is.
Existing mechanisms like set -e are unreliable, and shell scripts are often
flaky as a result.
The goal of Oil is:
Don't give anyone an excuse not to use
set -e
And this doc explains how.
Remember that bin/osh behaves exactly like a POSIX shell, so all your
existing scripts will continue to work, with their quirky error handling.
bin/oil has errexit on, so you don't need to write it explicitly. It also
has a bunch of options to fix the quirky behavior, including:
strict_errexit: Disallow surprising / dangerous programming patterns. It
will alert you when POSIX shell interpreters would do something surprising.more_errexit: Fail more often.inherit_errexit (bash 4.4 also has this)Here's some background knowledge on Unix shell, which will motivate the improvements in Oil.
(1) Shell has a global variable $? that stores the integer status of the last
command. For example:
echo hi returns 0ls /zzz will return an error like 2nonexistent-command returns 127(2) "Bare" Assignments are considered commands.
a=b is 0.a=$(false) is 1, because false returned 1.(3) Assignment builtins have their own exit status.
Surprisingly, the exit status of local a=$(false) is 0, not 1. That is,
simply adding local changes the exit status of an assignment.
The local builtin has its own status which overwrites $?, and you lose the
status of false.
(4) You can explicitly check $? for failure, e.g. test $? -eq 0 || die "fail".
The set -e / set -o errexit mechanism tries to automate these checks, but
it does it in a surprising way.
This rule causes a lot of problems:
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.
(5) Bash implement errexit differently than other shells. `shopt -s More details:
errexit differently.ls | grep foo, the variable $? is set to the exit status of grep.
set -o pipefail, then the status of a pipeline is the maximum of any
status.success/fail of a command and logical true/false are conflated in shell.
Oil has commands and expressions. Commands have a status but expressions don't.
TODO:
set +o errexit
my-complex-func
status=$?
other-func
status=$?
set -o errexit
shopt -u errexit {
var status = 0
my-complex-func
setvar status = $?
other-func
setvar status = $?
}
No:
if myfunc ... # internal exit codes would be thrown away
if ls | wc -l ; # first exit code would be thrown away
Yes:
if external-command ... # e.g. grep
if builtin ... # e.g. test
if $0 myfunc ... # $0 pattern
The $0 myfunc pattern wraps the function in an external command.