Re: `declare -f "a="' fails unnecessarily
Emanuele Torre writes: > `declare -f "something="' fails with the following error: > > $ declare -f 'a=x' > bash: declare: cannot use `-f' to make functions > That error is not very useful. Bash makes `declare -f' fail with that > error when an argument looks like an assignment. It's an interesting mess. Looking at the definition of "declare", the "=" is used to separate the name from the value being assigned to the name: declare [-aAfFgiIlnrtux] [-p] [name[=value] ...] So the statement above is an attempt to declare the name "a" as a function, with the value somehow being "x". There's a difficulty because recent Bashes have allowed function names that are not "names" in the Bash sense: fname () compound-command [redirection] function fname [()] compound-command [redirection] This defines a function named fname. [...] When in posix mode, fname must be a valid shell name and may not be the name of one of the POSIX special builtins. In default mode, a function name can be any unquoted shell word that does not contain $. name A word consisting only of alphanumeric characters and underâ scores, and beginning with an alphabetic character or an underâ score. Also referred to as an identifier. In default mode, you actually can do $ function a=b { printf hi\\n; } though you can't execute it: $ a=b foo bash: foo: command not found You say the error is not very useful, but it seems to me that the error is doing exactly what is intended; you *shouldn't* have an argument that looks like an assignment. IMO the fact that you can use "function" to declare a function with "=" in its name is a mis-feature. Dale
Re: `declare -f "a="' fails unnecessarily
On Dez 04 2022, Dale R. Worley wrote: > In default mode, you actually can do > $ function a=b { printf hi\\n; } > though you can't execute it: > $ a=b foo > bash: foo: command not found You just have to quote any part of the function name upto the equal sign to stop if from being interpreted as an assignment. $ \a=b foo hi -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1 "And now for something completely different."
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
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 ...