Re: declare XXX=$(false);echo $?

2022-12-02 Thread Martin D Kealey
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 $?

2022-12-02 Thread Dale R. Worley
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 $?

2022-12-02 Thread Chet Ramey

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 $?

2022-12-02 Thread Greg Wooledge
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 $?

2022-12-02 Thread David
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 $?

2022-12-02 Thread Ulrich Windl
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 ']'