Re: declare XXX=$(false);echo $?
On 12/2/22 8:26 PM, Martin D Kealey wrote: If anything is weird, it's that simple (bare) assignments set $? to 0 UNLESS there's a command substitution providing a status. Why not, if the assignment is performed successfully? POSIX says all errors in that context are fatal for non-interactive shells, but interactive shells continue. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
Re: [EXT] Re: declare XXX=$(false);echo $?
On Mon, Dec 5, 2022, at 2:47 AM, Ulrich Windl wrote: > So basically the behavior is as documented (not a bug), but the design > decision was poor: > > declare a > a=b > > has a different semantic as > declare a=b > > which I consider to be bad. You're free to think so, but this behavior is ubiquitous among Bourne-adjacent shells and is not about to change. % cat foo.sh export foo=$(false) echo "$?" % bash foo.sh 0 % ksh foo.sh 0 % zsh foo.sh 0 % dash foo.sh 0 % yash foo.sh 0 -- vq
Antw: [EXT] Re: declare XXX=$(false);echo $?
>>> Martin D Kealey schrieb am 03.12.2022 um 02:26 in Nachricht : ... > Found in the real code (intended to trigger a bug): >> declare ERRORS=0 ARGS=$(getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- >> "$@") >> > if [ $? -ne 0 ]; then >> usage >> fi >> > > That is a well-known anti-pattern that should be avoided. > > Some working equivalents would be: > ``` > declare ARGS=$( getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- "$@" ) > ERRORS=$? > (( ERRORS == 0 )) || usage > ``` > or: > ``` > declare ARGS ERRORS=0 > ARGS=$( getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- "$@" ) || > usage > ``` > > -Martin > > (PS: "Working" would be questionable, since putting `getopt` in a subshell > prevents it from updating "$@"; and `test $? = 0` and its variants are > pointless clutter.) Well, the code proved to work, and the pattern was found in /usr/share/getopt/getopt-parse.bash (of BASH 4.3): ... # Note that we use "$@" to let each command-line parameter expand to a # separate word. The quotes around "$@" are essential! # We need TEMP as the 'eval set --' would nuke the return value of getopt. TEMP=$(getopt -o 'ab:c::' --long 'a-long,b-long:,c-long::' -n 'example.bash' -- "$@") if [ $? -ne 0 ]; then echo 'Terminating...' >&2 exit 1 fi ...
Antw: [EXT] Re: declare XXX=$(false);echo $?
Dale, thanks for explaining. So basically the behavior is as documented (not a bug), but the design decision was poor: declare a a=b has a different semantic as declare a=b which I consider to be bad. Ulrich >>> "Dale R. Worley" schrieb am 02.12.2022 um 17:39 in Nachricht <878rjpahfz@hobgoblin.ariadne.com>: > Chet Ramey writes: >> On 12/2/22 5:28 AM, Ulrich Windl wrote: >>> Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") >>> There is no indication in the manual page that "declare" ignores the >>exit code of commands being executed to set values. >> >> Why do you think it should? `declare' has a well-defined return status. > > There it is, end of "SIMPLE COMMAND EXPANSION": > >If there is a command name left after expansion, execution proceeds > as >described below. Otherwise, the command exits. If one of the > expan‐ >sions contained a command substitution, the exit status of the > command >is the exit status of the last command substitution performed. > If >there were no command substitutions, the command exits with a status > of >zero. > > and: > >declare [-aAfFgiIlnrtux] [-p] [name[=value] ...] >typeset [-aAfFgiIlnrtux] [-p] [name[=value] ...] > [...] > The return value > is 0 unless an invalid option is encountered, an attempt is > made > to define a function using ``-f foo=bar'', an attempt is made > to > assign a value to a readonly variable, an attempt is made to > as‐ > sign a value to an array variable without using the compound > as‐ > signment syntax (see Arrays above), one of the names is not > a > valid shell variable name, an attempt is made to turn off > read‐ > only status for a readonly variable, an attempt is made to > turn > off array status for an array variable, or an attempt is made > to > display a non-existent function with -f. > > If you input "XXX=$(false)", there isn't a command name, it's a sequence > of assignments, and "the exit status of the command is the exit status > of the last command substitution performed". But if you input "declare > XXX=$(false)", you're executing the "declare" command, and the exit > status doesn't depend on the command substitution. > > Dale
Re: declare XXX=$(false);echo $?
On Fri, 2 Dec 2022 at 20:28, Ulrich Windl wrote: > Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") > "Surprising" is subjective. There is no indication in the manual page that "declare" ignores the exit > code of commands being executed to set values. > Framing this as `declare` "ignoring" something indicates a possible misunderstanding of the separate phases of execution. Every command (with exactly three exceptions) sets its own exit status without regard for any previous value of $?, including any set by $(...) expansions used to create the command in question. If anything is weird, it's that simple (bare) assignments set $? to 0 UNLESS there's a command substitution providing a status. The other two exceptions are `return` and `exit`, which use the previous $? as the default if no parameter is supplied. Like every other command, including "declare", sets its exit status independently of what $? is before it runs. So it's somewhat of a mystery why anyone would expect "declare" to be any different. (Actually, it's no mystery: cargo-cult coding is the norm, as the majority of people writing shell scripts have not read all of "man bash" and have little idea of how the shell is actually supposed to work. So perhaps Bash needs an officially sanctioned "beginners' guide".) Found in the real code (intended to trigger a bug): > declare ERRORS=0 ARGS=$(getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- > "$@") > if [ $? -ne 0 ]; then > usage > fi > That is a well-known anti-pattern that should be avoided. Some working equivalents would be: ``` declare ARGS=$( getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- "$@" ) ERRORS=$? (( ERRORS == 0 )) || usage ``` or: ``` declare ARGS ERRORS=0 ARGS=$( getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- "$@" ) || usage ``` -Martin (PS: "Working" would be questionable, since putting `getopt` in a subshell prevents it from updating "$@"; and `test $? = 0` and its variants are pointless clutter.)
Re: declare XXX=$(false);echo $?
Chet Ramey writes: > On 12/2/22 5:28 AM, Ulrich Windl wrote: >> Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") >> There is no indication in the manual page that "declare" ignores the >exit code of commands being executed to set values. > > Why do you think it should? `declare' has a well-defined return status. There it is, end of "SIMPLE COMMAND EXPANSION": If there is a command name left after expansion, execution proceeds as described below. Otherwise, the command exits. If one of the expanâ sions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed. If there were no command substitutions, the command exits with a status of zero. and: declare [-aAfFgiIlnrtux] [-p] [name[=value] ...] typeset [-aAfFgiIlnrtux] [-p] [name[=value] ...] [...] The return value is 0 unless an invalid option is encountered, an attempt is made to define a function using ``-f foo=bar'', an attempt is made to assign a value to a readonly variable, an attempt is made to asâ sign a value to an array variable without using the compound asâ signment syntax (see Arrays above), one of the names is not a valid shell variable name, an attempt is made to turn off readâ only status for a readonly variable, an attempt is made to turn off array status for an array variable, or an attempt is made to display a non-existent function with -f. If you input "XXX=$(false)", there isn't a command name, it's a sequence of assignments, and "the exit status of the command is the exit status of the last command substitution performed". But if you input "declare XXX=$(false)", you're executing the "declare" command, and the exit status doesn't depend on the command substitution. Dale
Re: declare XXX=$(false);echo $?
On 12/2/22 5:28 AM, Ulrich Windl wrote: Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") There is no indication in the manual page that "declare" ignores the exit code of commands being executed to set values. Why do you think it should? `declare' has a well-defined return status. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
Re: declare XXX=$(false);echo $?
On Fri, Dec 02, 2022 at 11:28:50AM +0100, Ulrich Windl wrote: > Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") https://mywiki.wooledge.org/BashPitfalls#pf27
Re: declare XXX=$(false);echo $?
On Fri, 2 Dec 2022 at 21:29, Ulrich Windl wrote: > Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") > There is no indication in the manual page that "declare" ignores > the exit code of commands being executed to set values. The above is not surprising at all. 'declare' is a builtin command. It succeeded. $ help declare | tail -n 3 Exit Status: Returns success unless an invalid option is supplied or a variable assignment error occurs. 'man bash' explains this comprehensively. The return value is 0 unless an invalid option is encountered, an attempt is made to define a function using ``-f foo=bar'', an attempt is made to assign a value to a readonly variable, an attempt is made to as‐ sign a value to an array variable without using the compound as‐ signment syntax (see Arrays above), one of the names is not a valid shell variable name, an attempt is made to turn off read‐ only status for a readonly variable, an attempt is made to turn off array status for an array variable, or an attempt is made to display a non-existent function with -f. Also, $(false) probably does not produce the value of $XXX that you expect. Try running 'echo $(false)'.
declare XXX=$(false);echo $?
Surprisingly "declare XXX=$(false);echo $?" outputs "0" (not "1") There is no indication in the manual page that "declare" ignores the exit code of commands being executed to set values. Actually I's consider it to be a ASH bug, not a documentation bug. Found in the real code (intended to trigger a bug): declare ERRORS=0 ARGS=$(getopt -o "$S_OPTS" -l "$L_OPTS" -n "$0" -- "$@") if [ $? -ne 0 ]; then usage fi ++ getopt -o e:i:v -l exclude:,include:,verbose -n ./buggy.sh -- add -vv -iHCTL_DEFS -k SAPDA_DEFS -- -p ./buggy.sh: invalid option -- 'k' + declare ERRORS=0 'ARGS= -v -v -i '\''HCTL_DEFS'\'' -- '\''add'\'' '\''SAPDA_DEFS'\'' '\''-p'\''' + '[' 0 -ne 0 ']'