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.
-
6No 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.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2015-06-06 22:47:30 +00:00Commented Jun 6, 2015 at 22:47 -
2This fails to early-out if you run
func && foo,if func then ... fior similar constructs which depend on the exit status offunc. See explanation.John Mellor– John Mellor2016-04-06 15:20:30 +00:00Commented 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?anon– anon2017-08-01 16:09:22 +00:00Commented 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_failwhich works just fine.anon– anon2017-08-01 16:19:18 +00:00Commented Aug 1, 2017 at 16:19 -
@RadonRosborough
pipefailwas 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_optionsin the function). This is not new and the online documentation is up-to-date, but not very easy to read.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2017-08-01 16:37:33 +00:00Commented 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.anon– anon2017-08-01 17:51:03 +00:00Commented 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