powershelldocker-composepowershell-5.0

Environment variables in Compose using Powershell with only 1 line


I know that you can pass environment variables to docker-compose.

docker-compose.yml

. . .
mysql:
    image: mariadb:10.2
    ports:
     - "${DB_PORT}:3306"
. . .

$ DB_PORT=3396 docker-compose up

However this only works using bash. I am using PowerShell and am trying to find an equivalent that is only a one line command.

PS> $env:DB_PORT:3306 docker-compose up does not work. Neither does multiline

$env:DB_PORT=3396 `
>> docker-compose -up

The error I get is Unexpected token 'docker-compose' in expression or statement.

If I do it one at a time it does work...

PS> $env:DB_PORT=3396
PS> docker-compose -up

Is there not way to do this in PowerShell when the equivalent in bash is ridiculously simple?


Solution

  • POSIX-like shells such as bash offer a way to set environment variables in a command-scoped way, simply by prepending <varName>=<value> pairs directly to a command, as the following example demonstrates:

    $ foo=bar bash -c 'echo "[$foo]"'; echo "[$foo]"
    [bar]
    []
    

    foo=bar defines environment variable foo for the bash -c '...' child process only; the next command - echo ... - does not see this variable.


    PowerShell has NO equivalent construct as of v7.4.

    To add support in the future with at least similar syntax is the subject of a long-standing feature request, GitHub issue #3316.

    For now, the best you can do is to define the environment variable of interest first, in a separate statement, using ;, PowerShell's statement separator. Any external utility you invoke thereafter - which invariably runs in a child process - will see it, but note that the environment variable will remain in effect in the current PowerShell session, unless you manually remove it:

    # Set the env. variable, call the command that should see it,
    # remove it afterwards.
    PS> $env:foo = 'bar'; bash -c 'echo "[$foo]"'; $env:foo = $null
    [bar]
    

    Note how $env:foo = $null i.e., setting the environment variable to $null is the same as removing it; alternatively, you could all Remove-Item env:foo

    If you also want to restore a pre-existing value afterwards:

    $env:foo = 'original'
    
    # Temporarily change $env:foo to a different value, invoke the
    # program that should see it, then restore the previous value.
    & { $org, $env:foo = $env:foo, 'bar'; bash -c 'echo "[$foo]"'; $env:foo = $org }
    
    $env:foo
    

    The above yields:

    [bar]
    original
    

    showing that while the bash process saw the temporary value, bar, the original value of $env:foo was restored afterwards.


    Also note another important difference: