$ a=one; echo $a
one
$ a=two echo $a
one
$ echo $a
one
The value of a
will be initialized to 'two' but why is it displaying 'one'?
$ a=one; echo $a
one
$ a=two echo $a
one
$ echo $a
one
The value of a
will be initialized to 'two' but why is it displaying 'one'?
Same line initialization of env variables is only available for sub shells.
It will be more evident from these examples:
unset a
a=two echo "<$a>"
<>
a=two bash -c 'echo "<$a>"'
<two>
echo "<$a>"
<>
In the 2nd snippet it prints <two>
because we're spawning a sub-shell using bash -c
.
This is due to the order in which the shell processes substitutions and variables. According to POSIX rules for a shell:
When a given simple command is required to be executed (that is, when any conditional construct such as an AND-OR list or a case statement has not bypassed the simple command), the following expansions, assignments, and redirections shall all be performed from the beginning of the command text to the end:
The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing in steps 3 and 4.
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.
Redirections shall be performed as described in Redirection.
Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal prior to assigning the value.
That means that the variable assignment is performed after parameter expansion has occurred, e.g. $a
is expanded before the a=
variable assignment for that command has been processed. The new value of a
will be passed into the execution environment of the command but it won't be of any use in this case with echo
.
You can perhaps see better what's going on if you use a variable that does not already exist.
$ unset a
$ a=two echo \($a\)
()
$ a=one
$ a=two echo \($a\)
(one)
Here's an example where you can see that the variable assignment is passed to the execution environment of the command that is executed:
$ a=one
$ a=two python -c 'import os;print(os.environ["a"])'
two