How do I set an environment variable on the command line and have it appear in commands?
This is because the shell expands the variable in the command line before it actually runs the command and at that time the variable doesn't exist. If you use
TEST=foo; echo $TEST
it will work.
export
will make the variable appear in the environment of subsequently executed commands (for on how this works in bash see help export
). If you only need the variable to appear in the environment of one command, use what you have tried, i.e.:
TEST=foo your-application
The shell syntax describes this as being functionally equivalent to:
export TEST=foo
your-application
unset TEST
See the specification for details.
I suspect you want to have shell variables to have a limited scope, rather than environment variables. Environment variables are a list of strings passed to commands when they are executed.
In
var=value echo whatever
You're passing the var=value
string to the environment that echo receives. However, echo
doesn't do anything with its environment list¹ and anyway in most shells, echo
is built in and therefore not executed.
If you had written
var=value sh -c 'echo "$var"'
That would have been another matter. Here, we're passing var=value
to the sh
command, and sh
does happen to use its environment. Shells convert each of the variables they receive from their environment to a shell variable, so the var
environment variable sh
receives will be converted to a $var
variable, and when it expands it in that echo
command line, that will become echo value
. Because the environment is by default inherited, echo
will also receive var=value
in its environment (or would if it were executed), but again, echo
doesn't care about the environment.
Now, if as I suspect, what you want is to limit the scope of shell variables, there are several possible approaches.
Portably (Bourne and POSIX):
(var=value; echo "1: $var"); echo "2: $var"
The (...) above starts a sub-shell (a new shell process in most shells), so any variable declared there will only affect that sub-shell, so I'd expect the code above to output "1: value" and "2: " or "2: whatever-var-was-set-to-before".
With most Bourne-like shells, you can use functions and the "local" builtin:
f() {
local var
var=value
echo "1: $var"
}
f
echo "2: $var"
With zsh, you can use inline functions:
(){ local var=value; echo "1: $var"; }; echo "2: $var"
or:
function { local var=value; echo "1: $var"; }; echo "2: $var"
With bash and zsh (but not ash, pdksh or AT&T ksh), this trick also works:
var=value eval 'echo "1: $var"'; echo "2: $var"
A variant that works in a few more shells (dash
, mksh
, yash
) but not zsh
(unless in sh
/ksh
emulation):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(using command
in front of a special builtin (here eval
) in POSIX shells removes their specialness (here that variables assignments in from of them remain in effect after they have returned))
¹ Stricktly speaking, that's not completely true. Several implementations will care about the localisation environment variables (LANG
, LOCPATH
, LC_*
...), the GNU implementation cares about the POSIXLY_CORRECT
environment variable (compare env echo --version
with POSIXLY_CORRECT=1 env echo --version
on a GNU system).
You're doing it correctly, but the bash syntax is easy to misinterpret: you could think that echo $TEST
causes echo
to fetch TEST
env var then print it, it does not. So given
export TEST=123
then
TEST=456 echo $TEST
involves the following sequence:
The shell parses the whole command line and executes all variable substitutions, so the command line becomes
TEST=456 echo 123
It creates the temp vars set before the command, so it saves the current value of
TEST
and overwrites it with 456; the command line is nowecho 123
It executes the remaining command, which in this case prints 123 to stdout (so shell command that remains didn't even use the temp value of
TEST
)It restores the value of
TEST
Use printenv instead, as it does not involve variable substitution:
>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>