Is there such a feature or can it be emulated reasonably easily?
I want the same behavior except it should return
where set -e
would have caused a call to exit
.
3 Answers
Sub shell might be useful.
func() {(set -e
echo a
ehco b
echo c
)}
func
func
func
This script produces:
a
script.sh: line 3: ehco: command not found
a
script.sh: line 3: ehco: command not found
a
script.sh: line 3: ehco: command not found
Alternatively you might be interested in this try/catch implemetation in bash.
-
5No need for the braces in this case:
func () ( … )
is equivalent. Note that since the function is executed in a subshell, its variable assignments, redirections, etc. won't affect the caller. Jun 6, 2015 at 22:47 -
2This fails to early-out if you run
func && foo
,if func then ... fi
or similar constructs which depend on the exit status offunc
. See explanation. Apr 6, 2016 at 15:20
You can set the ERR
trap, which is executed whenever a command returns a nonzero status.
In bash, it's a bit fiddly because traps are not local to functions. By default, traps are not inherited by subshells or subfunctions; call set -E
to change this. Here's some demo code.
#!/bin/bash
subroutine () {
false
echo "Subroutine continued after status $?"
}
trapper () {
local i ret
trap 'ret=$?
echo "Command $BASH_COMMAND returned status $ret"
for ((i=0; i<$((${#FUNCNAME[@]}-1)); i++)) do
echo " from ${FUNCNAME[$i]} at ${BASH_SOURCE[$((i+1))]} line ${BASH_LINENO[$((i+1))]}"
done
return $ret' ERR
trap 'ret=$?; trap - ERR RETURN; return $ret' RETURN
echo ok
subroutine
echo "By default, the ERR trap is not inherited"
false
echo "You won't see this"
}
main () {
trapper
echo "trapper returned status $?"
false
echo "still there"
}
main
In zsh, you can define the TRAPZERR
function instead of setting a trap for ERR
(for compatibility) or ZERR
(on systems with a signal called SIGERR
— I don't know of any). But if all you want to do is return immediately (and not e.g. print an error message), it's simpler: just set the err_return
option. Options are global by default; set the local_options
option to make them local to the calling function (if the local_options
option is set when a function returns, the options from the time the function was called are restored). Traps are also global by default. Options and traps are inherited in function calls.
myfunction () {
setopt local_options err_return
false
echo not executed
}
-
It does not look like the zsh solution has the behavior of
set -o pipefail
, justset -e
. Any way to fix this? Aug 1, 2017 at 16:09 -
Oh, silly me assuming the online docs would be up to date. Recent versions of zsh have a
setopt pipe_fail
which works just fine. Aug 1, 2017 at 16:19 -
@RadonRosborough
pipefail
was outside the scope of the question. In bash, ksh and zsh you can doset -o pipefail
(note that this isn't local to the function, except in zsh if you callsetopt local_options
in the function). This is not new and the online documentation is up-to-date, but not very easy to read. Aug 1, 2017 at 16:37 -
You're right that the official manual at zsh.sourceforge.net/Doc/Release/Options.html is perfectly well up to date. I was looking at linux.die.net/man/1/zshoptions from Google, which I should have been more clear about. Aug 1, 2017 at 17:51
With ksh93
, if you use ksh
's own syntax for funtion definition (function f {...;}
), then options and traps have a local scope. So there, you can do:
function f {
trap 'return 99' ERR
set -e
echo foo
false
echo never output
}
f
echo "f exited with status $?"
Which gives:
foo
f exited with status 99