I am trying to unset some variables and export others using command substitution. This works:
$(echo "
export TEST_A=1
export TEST_B=2
")
And this too:
$(echo "
unset TEST_A
unset TEST_B
")
However, this fails with Bash 4.3.30(1)-release on both OSX and Debian Jessie:
$(echo "
unset TEST_A
export TEST_B=1
")
# bash: unset: `TEST_B=1': not a valid identifier
Is this an expected behavior, and how can one unset and export multiple variables using command substitution?
To provide some context: here is the related issue in boot2docker.
Best Answer
In:
being
$(...)
, just one expansion is parsed as a simple command.So that
$(...)
expansion undergoes the split+glob operator. The output ofecho
is trimmed of its trailing newline characters and split into several words on IFS characters (newline, space and tab by default):export
TEST_A=1
export
TEST_B=2
And each word undergoes globbing. Here they expand to themselves since they don't contain wildcard characters. So after globbing, we still have the same list of four strings.
The command to run is derived from the first one. Here
export
and all those strings are passed as arguments to that command. So, here, it's as if you had written:So you're exporting the
TEST_A
variable with value 1, theexport
variable without changing its value and theTEST_B
variable with value 2.In the last one, you're running:
If you want the output of
echo
to be treated as shell code to interpret, that's where you want to useeval
and not use the split+glob operator (quote your command substitution):That one is also a simple command. Two strings:
eval
and<newline><spaces>unset TEST_A<newline><spaces>export TEST_B=1
.eval
evaluates the content of its arguments as shell code. So it runs those two shell command lines:unset TEST_A
andexport TEST_B=1
(again, two simple commands).