'How to pass environment variables from a string to a bash command
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.
Solution 1:[1]
If you can, use a different format.
There are several better options:
An array.
envvars=( AAA=1 BBB=2 CCC=3 ) env "${envvars[@]}" node.js index.jsA 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 ```
But whatever you do, don't use 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
evalis started, your parameters and globs are expanded. Let's say your current directory contains files named1and2:'eval' 'BBB=1' 'CCC=2' 'DDD="value' '1' '2' 'with' '1' '2' 'spaces"' 'node' 'foo.js'Then,
evaltakes 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.jsThen that string is parsed from the very beginning
...which means that if instead of having a file named
1you had a file named$(rm -rf ~)(a perfectly valid filename!), you would have a very, very bad day.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
