If I run

FOO=bar docker run -it -e FOO=$FOO debian env

That environment variable is not set in the command output for the env command.


But if I run

FOO=bar; docker run -i -t --rm -e FOO=$FOO debian:stable-slim env

Then the variable is available from the container and also exported into my current shell environment.

echo $FOO

I expect this behavior with export FOO=bar but why does that happen with ; too?

  • 8
    Are you sure your examples are correct? If I do foo=bar then run echo "$foo" I see bar, are you trying to do foo=bar some_other_command in the first example? – Eric Renouf May 20 '19 at 20:15
  • digging into it more it doesn't look like the ; matters until I run bash again. I'll clarify the question with a more concrete example of what I was trying to do. – Rothgar May 20 '19 at 20:36
  • What shell are you using? OS? Note: environment variables are listed by env for example. A simple echo "$var" prints the value of a variable (environment or not). – Isaac May 20 '19 at 20:36
  • Please always use -e FOO="$FOO" because -e FOO=$FOO is almost always a bug. – kubanczyk May 21 '19 at 19:29

No, FOO=bar; does not export the variable into my environment

A var is set in the (present) environment only if it was previously exported:

$ export foo
$ foo=bar
$ env | grep foo

A variable is set in the environment of a command when it is placed before the command. Like foo=bar command. And it only exists while the command runs.

$ foo=bar bash -c 'echo "foo is = $foo"'
foo is = bar

The var is not set for the command line (in the present shell):

$ foo=bar bash -c echo\ $foo

Above, the value of $foo is replaced with nothing by the present running shell, thus: no output.

Your command:

$ FOO=bar docker run -it -e FOO=$FOO debian env

is converted to the actual string:

$ FOO=bar docker run -it -e FOO= debian env

by the present running shell.

If, instead, you set the variable (in the present running shell) with foo=bar before running the command, the line will be converted to:

$ FOO=bar; docker run -it -e FOO=bar debian env

A variable set to the environment of a command is erased when the command returns:

$ foo=bar bash -c 'echo'; echo "foo was erased: \"$foo\""

Except when the command is a builtin in some conditions/shells:

$ ksh -c 'foo=bar typeset baz=quuz; echo $foo'
|improve this answer|||||
  • 2
    The variable FOO is also not exported to the current shell environment, but set as a shell variable, unless it has been previously exported. – Johan Myréen May 20 '19 at 21:01
  • Not knowing anything about Docker, I wonder if it would actually work if the -e FOO=$FOO thing (which I presume is used to set an environment variable) is removed since FOO is set in Docker's environment. – Kusalananda May 20 '19 at 21:03
  • Sorry, I should have posted this as a comment to the question, where Rothgar said that FOO was also "exported into my current shell environment." – Johan Myréen May 21 '19 at 3:58

There are a number of variations to consider:

  1. Just doing FOO=bar creates a variable named FOO with value bar, but that variable isn't passed along to new processes:

    $ echo $FOO
    $ FOO=bar
    $ echo $FOO
    $ bash        # Start a new bash process
    $ echo $FOO
                  # Variable is not set in the new process
    $ exit        # Exit new bash process
  2. Running FOO=bar <command> will run the given command with the variable set (but doesn't affect the original shell's environment):

    $ echo $foo
    $ FOO=baz bash   # start a new bash process
    $ echo $FOO
    $ exit           # exit the new bash process
    $ echo $FOO      
                     # No FOO in the original bash process
  3. Doing FOO=foo; <command> is equivalent to (1); putting a semicolon between two commands is equivalent to running those two commands on two separate lines:

    $ FOO=foo; echo $FOO
    $ bash
    $ echo $FOO
    $ exit
    $ echo $FOO
  4. Using export will pass a variable in the shell's environment to newly-created processes:

    $ export FOO=bar
    $ echo $FOO    # Value set in original shell
    $ bash         # Start another shell
    $ echo $FOO
    bar            # Value was passed along to new process
    $ exit
|improve this answer|||||

FOO=bar docker run -it -e FOO=$FOO debian env

Here the $FOO from FOO=$FOO will be expanded before the FOO=bar assignment happens.

You can check that with a more straight-forward example:

FOO=second echo FOO=$FOO
=> FOO=first

FOO=third; echo FOO=$FOO
=> FOO=third

The FOO=bar cmd form will really set FOO=bar in the environment of cmd, but a command like docker does not automatically export its own environment into the container, but the environment vars have to be added explicitly with the -e switch.

Again, a more straightforward demo would be:

FOO=after env - FOO=$FOO printenv FOO
=> before
|improve this answer|||||
  • This seems to me the most concise correct answer to the question. – kojiro May 22 '19 at 1:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.