Lone Learner Lone Learner - 1 year ago 45
Bash Question

Why does field splitting not occur after parameter expansion in an assignment statement in shell?

Consider the following two assignments.

$ a="foo bar"
$ b=$a
$ b=foo bar
bash: bar: command not found

Why does the second assignment work fine? How is the second command any different from the third command?

I was hoping the second assignment to fail because


would expand to

b=foo bar

is not within double-quotes,
foo bar
is not quoted, therefore field-splitting should occur (as per my understanding) which would result in
to be considered an assignment and
to be a command that cannot be found.

Summary: I was expecting the 2nd command to fail for the same reason that caused the 3rd command to fail. Why does the 2nd command succeed?

I went through the POSIX but I am unable to find anything that specifies that field splitting won't occur after parameter expansion that occurs in an assignment.

I mean anywhere else field splitting would occur for an unquoted parameter after parameter expansion. For example,

$ a="foo bar"
$ printf "[%s] [%s]\n" $a
[foo] [bar]

See Section 2.6.5.

After parameter expansion (Parameter Expansion), command substitution (Command Substitution), and arithmetic expansion (Arithmetic Expansion), the shell shall scan the results of expansions and substitutions that did not occur in double-quotes for field splitting and multiple fields can result.

So which part of the POSIX standard prevents field splitting when parameter expansion occurs in an assignment statement?

Answer Source

In 2.9.1, "Simple Commands":

The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing in steps 3 and 4.

Step 2 -- which is explicitly skipped in this case per the above text -- reiterates that it ignores assignments when performing expansion and field splitting:

The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.

Thus, it's step 2 that determines the command to run (based on contents other than variable assignments and redirections), which addresses the b=$a case given in your question.

Step 4 performs other expansions -- "tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal" -- for assignments. Notably, field splitting is not a member of this set. Indeed, it's explicit in 2.6 that none of these create multiple words in and of themselves:

Tilde expansions, parameter expansions, command substitutions, arithmetic expansions, and quote removals that occur within a single word expand to a single field. It is only field splitting or pathname expansion that can create multiple fields from a single word. The single exception to this rule is the expansion of the special parameter '@' within double-quotes, as described in Special Parameters.