'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.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 ```
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
eval
is started, your parameters and globs are expanded. Let's say your current directory contains files named1
and2
:'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.
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 |