Search code examples
bashunixenvironment-variablesenvironment

Setting environment variable for one program call in bash using env


I am trying to invoke a shell command with a modified environment via the command env.

According to the manual

env HELLO='Hello World' echo $HELLO

should echo Hello World, but it doesn't. If I do

HELLO='Hello World' bash -c 'echo $HELLO'

it prints Hello World as expected (thanks to this answer for this info).

What am I missing here?


Solution

  • It's because in your first case, your current shell expands the $HELLO variable before running the commands. And there's no HELLO variable set in your current shell.

    env HELLO='Hello World' echo $HELLO
    

    will do this:

    • expand any variables given, in this case $HELLO
    • run env with the 3 arguments 'HELLO=Hello World', 'echo' and '' (an empty string, since there's no HELLO variable set in the current shell)
    • The env command will run and set the HELLO='Hello World' in its environment
    • env will run echo with the argument '' (an empty string)

    As you see, the current shell expanded the $HELLO variable, which isn't set.

    HELLO='Hello World' bash -c 'echo $HELLO'
    

    will do this:

    • set the variable HELLO='Hello World for the following command
    • run bash with the 2 arguments '-c' and 'echo $HELLO'
    • since the last argument is enclosed in single quotes, nothing inside it is expanded
    • the new bash in turn will run the command echo $HELLO
    • To run echo $HELLO in the new bash sub-shell, bash first expands anything it can, $HELLO in this case, and the parent shell set that to Hello World for us.
    • The subshell runs echo 'Hello World'

    If you tried to do e.g. this:

    env HELLO='Hello World' echo '$HELLO'
    
    • The current shell would expand anything it can, which is nothing since $HELLO is enclosed in single quotes
    • run env with the 3 arguments 'HELLO=Hello World', 'echo' and '$HELLO'
    • The env command will run and set the HELLO='Hello World' in its environment
    • env will run echo with the argument '$HELLO'

    In this case, there's no shell that will expand the $HELLO, so echo receives the string $HELLO and prints out that. Variable expansion is done by shells only.