This is a minimal example of a more complex script I'm writing. The key thing I want to do is have $FOO
visible to that sub shell in the second line of function foo
.
However, as shown, it's not visible for the first evaluation but oddly visible for the second evaluation.
❯ function foo() {
echo "export FOO=BAR"
echo "export CAR=\$(echo \$FOO)"
}
~
❯ eval $(foo)
~
❯ echo $CAR
~
❯ eval $(foo)
~
❯ echo $CAR
BAR
eval $(foo)
is expanded to:
eval 'export FOO=BAR export CAR=$(echo $FOO)'
The export
has the effect of causing both assignments to be processed 'at the same time' and since FOO
is not known prior to this line of code the second assignment becomes CAR=$(echo '')=''
. It's only on the 2nd eval $(foo)
that FOO
has a value so CAR=BAR
.
To get around this side effect and have CAR=BAR
(for the first eval $(foo)
) you can either remove the export
or have the function print a ;
between the two export
s (explicitly separate the export
s as two separate commands), eg:
# remove 'export'
foo() {
echo "FOO=BAR"
echo "CAR=\$(echo \$FOO)"
}
# explicitly separate into 2 commands via a ';'
foo() {
echo "export FOO=BAR ;" # notice the ';' appended on the end
echo "export CAR=\$(echo \$FOO)"
}
For the 2nd foo()
definition the eval $(foo)
is expanded to:
eval 'export FOO=BAR ; export CAR=$(echo $FOO)'
With two separate commands FOO
is assigned a value before we parse/execute CAR=$(echo $FOO)
.
We can see this behavior of export
with a simpified example (sans the issues mentioned in Gordon Davisson's comment):
$ export A=3 B="$A"
$ typeset -p A B
declare -x A="3"
declare -x B="" # A does not have a value so B=""
$ export A=3 B="$A"
$ typeset -p A B
declare -x A="3"
declare -x B="3" # A now has a value (from 1st run) so B=3