Date:        Sat, 26 Sep 2026 10:46:59 -0400
    From:        Zachary Santer <[email protected]>
    Message-ID:  
<CABkLJULgXg_pfxH5TGxgQOCnykG1i=4ncgbujx3clm04yvp...@mail.gmail.com>

  | The parser has to do a bunch of special handling for compound
  | assignment statements as arguments to declaration commands.

It does, assuming one buys into the declaration utility stuff at all,
which is kind of necessary for array assignments in these commands
(not that the assignment ever needs to be in the "declaration" command,
just do them as separate assignments later, or in the case of readonly,
before the declaration).

  | This doesn't work either:
  | $ dash_A='-A'
  | $ declare ${dash_A} assoc=( [zero]=0 [one]=1 [two]=2 )

But if you accept the declaration utility syntax, all of that
should work.   What isn't required to work is

        declare=declare
        $declare .... # anything which needs special parsing

But POSIX (once it decided to add declaration utilities, to make
shells like bash happy) defined the arg processing to work like:

    If there is a command name and it is recognized as a declaration utility,
    then any remaining words after the word that expanded to produce the
    command name, that would be recognized as a variable assignment in
    isolation, shall be expanded as a variable assignment (tilde expansion
    after the first <equals-sign> and after any unquoted <colon>, parameter
    expansion, command substitution, arithmetic expansion, and quote removal,
    but no field splitting or pathname expansion); while remaining words that
    would not be a variable assignment in isolation shall be subject to regular
    expansion (tilde expansion for only a leading <tilde>, parameter expansion,
    command substitution, arithmetic expansion, field splitting, pathname
    expansion, and quote removal). For all other command names, ...

POSIX has no arrays, and hopefully it is going to stay that way, so the
only real difference this makes to a POSIX shell, is that it allows

        export var=$1

rather than requiring

        export "var=$1"
or
        export var="$1"

(or some similar variation, the opening " could be positioned anywhere
from just before the 'v' to just before the '$').

That benefit, if it is one at all, wouldn't have been worth the pain that
declaration utilities add to the parser, they need to be recognised just
like reserved words (except a reserved word can't be quoted, or result from
an expansion, whereas a declaration utility name can be ... it just isn't
required to be recognised as a declaration utility if it is).

The actual reason for adding the things is so the parser can switch into
a different mode when it sees array assignments in a declaration utility,
just as it does when it sees one in a variable assignment, for those shells
which support arrays, and have a syntax to allow literal arrays to be written.
That is, so the '(' doesn't become an operator, and act as a word separator,
and probably a syntax error, but instead remains a part of the word.

Note that in the above, there is no requirement on the order or content
of any words given as args to a declaration utility that aren't in the
correct var-assign type syntax, so the quoted, or expansion words that have
been shown to affect how bash parses the rest of the line should really
not be making any difference to anything, they're just words, which should
be processed the same as any other word, when the command is actually
executed.   Only the var-assign lookalike words get special processing, but
should get it wherever they appear in the arg list of the declaration utility.

  | You can always just separate the declare command and the compound
  | assignment statement:

Yes, that's what everyone should be doing, always.   The orginal Bourne
shell had no "assignments as args to 'declaration' type commands" at all,
just
        export var ...
no
        export var=value

That was never needed, and was actually an idiotic extension to add,
all to save people needing to write the name of the variable twice...

        export var; var=value

Meaningless.   Unfortunately far too entrenched to do away with now.

kre



Reply via email to