Running the following code:
a=one; echo $a
a=two echo $a
a=three echo $a >$a
results in
one
one
and a created file with name "one" with content "one"
Why the variable didn't change to two
at line 2 and to three
at line 3?
Running the following code:
a=one; echo $a
a=two echo $a
a=three echo $a >$a
results in
one
one
and a created file with name "one" with content "one"
Why the variable didn't change to two
at line 2 and to three
at line 3?
An assignment does something different when it's used as a command by itself vs. as a prefix to some other command (e.g. echo
). When used as a command by itself, it sets a shell variable to that value. When used as a prefix to some other command, it sets an that variable in the environment of the command but not in the shell.
So, look at the first example, a=one; echo $a
, where the semicolon makes this two commands on the same line. The first command sets the shell variable a
to the value "one", and then for the second command the shell expands a
to "one", and then passes that as an argument to echo
.
In the second example, a=two echo $a
, the assignment is a prefix to the echo
command, so echo
will be executed with a
set to "two" in its environment. But the $a
gets expanded by the shell, not by the echo
command, and a
is still set to "one" as a shell variable, so that value gets used.
The third example, a=three echo $a >$a
, is a lot like the second. The shell expands both $a
s to "one" (since that's the value of the shell variable), then executes echo one
with a
set to "three" in its environment and output directed to a file named "one".
BTW, there's another complication I haven't mentioned: export
ing shell variables. By default, shell variables are not set in the environment of commands that the shell executes. That is, they are shell variables, not environment variables. But if you export
a shell variable, it becomes an environment variable and will be inherited by subsequent commands run by that shell. So...
This sets a shell variable, which will not be passed on to commands' environments:
a=one
This sets an environment variable for this command only, not for the shell or later commands:
b=two somecommand
This sets an environment variable in the shell, so it'll be available to the shell and all subsequent commands run from that shell:
export c=three
This does the same thing:
d=four
export d
You can export shell variables to the environment before, after, or while assigning to them.
Run Shellcheck on your script:
In x.sh line 2:
a=two echo $a
^-- SC2097: This assignment is only seen by the forked process.
^-- SC2098: This expansion will not see the mentioned assignment.
In x.sh line 3:
a=three echo $a >$a
^-- SC2097: This assignment is only seen by the forked process.
^-- SC2098: This expansion will not see the mentioned assignment.
^-- SC2094: Make sure not to read and write the same file in the same pipeline.
^-- SC2094: Make sure not to read and write the same file in the same pipeline.
Then look up the SC.... codes, e.g., SC2097 as needed.
In this case, your command is var=... someCommand with params
so the variable is set just for that command, i.e., in that process.
That's also why the first line with the semicolon (a=one; echo $a
) is different. man bash
states:
Commands separated by a ; are executed sequentially
So you set the variable, then run the echo
as two separate actions.