Reputation: 9750
I have a variable AAA
which is in this format
AAA='BBB=1 CCC=2 DDD=3'
How can I use this to set environment variables BBB
, CCC
and DDD
in a command I run (without permanently exporting them to the shell)? That is, I want to use to use the above to do something identical to:
# this works correctly: node is run with AAA, BBB, and CCC in its environment
BBB=1 CCC=2 DDD=3 node index.js
...however, when I try:
# this does not work: AAA=1 is run as a command, so it causes "command not found"
$AAA node index.js
...it tries to run BBB=1
as a command, instead of parsing the assignment as a variable to set in node
's environment.
Upvotes: 3
Views: 5836
Reputation: 295914
There are several better options:
An array.
envvars=( AAA=1 BBB=2 CCC=3 )
env "${envvars[@]}" node.js index.js
A NUL-delimited stream (the ideal format to use to save environment variables in a file -- this is the format your operating system uses for /proc/self/environ
, for example).
Saving to a file:
```
printf '%s\0' 'foo=bar' \
'baz=qux' \
$'evil=$(rm -rf importantDir)\'$(rm- rf importantDir)\'\nLD_LIBRARY_PATH=/tmp/evil.so' \
> envvars
```
...or, even more simply (on Linux):
```
# save all your environment variables (as they existed at process startup)
cp /proc/self/environ envvars
```
Restoring from that file, and using it:
```
mapfile -d '' vars <envvars
env "${vars[@]}" node.js
```
eval
Remember that evil
environment variable I set above? It's a good example of a variable that poorly-written code can't set correctly. If you try to run it through eval
, it deletes all your files. If you try to read it from a newline-delimited (not NUL-delimited) file, it sets another LD_LIBRARY_PATH
variable that tells your operating system to load a shared library from an untrusted/untrustworthy location. But those are just a few cases. Consider also:
## DO NOT DO THIS
AAA='BBB=1 CCC=2 DDD="value * with * spaces"'
eval $AAA node foo.js
Looks simple, right? Except that what eval
does with it is not simple at all:
First, before eval
is started, your parameters and globs are expanded. Let's say your current directory contains files named 1
and 2
:
'eval' 'BBB=1' 'CCC=2' 'DDD="value' '1' '2' 'with' '1' '2' 'spaces"' 'node' 'foo.js'
Then, eval
takes all the arguments it's passed, and gloms them all together into a single string.
eval "BBB=1 CCC=2 DDD="value 1 2 with 1 2 spaces" node foo.js
Then that string is parsed from the very beginning
...which means that if instead of having a file named 1
you had a file named $(rm -rf ~)
(a perfectly valid filename!), you would have a very, very bad day.
Upvotes: 4