Shell's option 'errexit' works unexpectedly when command returning non-zero is called in `local` variable definition statement. Let's see on example: f2() { echo -n "f2(): " >/dev/stderr set -o | grep errexit >/dev/stderr echo "subsh=$BASH_SUBSHELL" >/dev/stderr echo 'Failed' >/dev/stderr return 1 } f1() { echo -n "f1(): " >/dev/stderr set -o | grep errexit >/dev/stderr echo A >/dev/stderr local v="$(f2)" echo B >/dev/stderr return 0 } set -e echo -n "main(): " >/dev/stderr set -o | grep errexit >/dev/stderr f1 exit 0 Run this script by bash: $ bash ./t.sh ; echo r=$? main(): errexit on f1(): errexit on A f2(): errexit off subsh=1 Failed B r=0 Despite the f2()'s non-zero return code, script have not terminated immediately after f2() call. Also, you may notice, that 'errexit' is not set in f2() (this is because bash's non-standard behavior (see 'COMMAND EXECUTION ENVIRONMENT' section in bash(1); this is only the case in _not_ posix mode). If, though, i run this script by dash, 'errexit' will be inherited by subshell spawned by command substitution, but f2()'s non-zero return code still does not abort the script: $ dash ./t.sh ; echo r=$? main(): errexit on f1(): errexit on A f2(): errexit on subsh= Failed B r=0 Now, let's try to call f2() in variable assignment instead. f1() function will then look like f1() { echo -n "f1(): " >/dev/stderr set -o | grep errexit >/dev/stderr echo A >/dev/stderr local v='' v="$(f2)" echo B >/dev/stderr return 0 } Run by bash: $ bash ./t.sh ; echo r=$? main(): errexit on f1(): errexit on A f2(): errexit off subsh=1 Failed r=1 and by dash: $ dash ./t.sh ; echo r=$? main(): errexit on f1(): errexit on A f2(): errexit on subsh= Failed r=1 And both of them abort script immediately after f2() call. So, it seems, like the problem is in `local` (i don't say this is bug). Note1. Let's also test bash's `declare` builtin. First call f2() from command substitution in `declare` variable definition statement: set -e echo -n "main(): " >/dev/stderr set -o | grep errexit >/dev/stderr echo AAA >/dev/stderr declare v="$(f2)" echo BBB >/dev/stderr exit 0 Run by bash $ bash ./t.sh ; echo r=$? main(): errexit on AAA f2(): errexit off subsh=1 Failed BBB r=0 and the result is the same as with `local`. Now, call f2() from variable assignment: set -e echo -n "main(): " >/dev/stderr set -o | grep errexit >/dev/stderr echo AAA >/dev/stderr declare v='' v="$(f2)" echo BBB >/dev/stderr exit 0 and run by bash $ bash ./t.sh ; echo r=$? main(): errexit on AAA f2(): errexit off subsh=1 Failed r=1 and the result is again the same as with `local` and now it works.
DISCLAIMER. English language used here only for compatibility (ASCII only), so any suggestions about my bad grammar (and not only it) will be greatly appreciated.
понедельник, 12 декабря 2011 г.
shell's 'errexit' option and variable definition.
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий