Search code examples
dockermakefilegnu-makevariable-expansion

Escape $ in variable passed to docker run command


I can't figure out how to escape the dollar sign in order to access a variable defined in an environment in docker, when executing the command from a makefile.

This is a minimal representation of my setup and I'm trying to echo /mypath

define create-test
so-test-$1:
    docker run \
        --rm \
        -t \
        --env SRC="/mypath" \
        ubuntu:xenial \
        /bin/bash -c "$2"
endef


$(eval $(call create-test,1,echo $SRC ))
$(eval $(call create-test,2,echo $$SRC ))
$(eval $(call create-test,3,echo $$$$SRC ))
$(eval $(call create-test,4,echo $$$$$$$$SRC ))

The outputs are

$ make so-test-1
docker run --rm -t --env SRC="/mypath" ubuntu:xenial /bin/bash -c "echo RC "
RC
$ make so-test-2
docker run --rm -t --env SRC="/mypath" ubuntu:xenial /bin/bash -c "echo RC "
RC
$ make so-test-3
docker run --rm -t --env SRC="/mypath" ubuntu:xenial /bin/bash -c "echo $SRC "

$ make so-test-4
docker run --rm -t --env SRC="/mypath" ubuntu:xenial /bin/bash -c "echo $$SRC "
6526SRC

I know the environment variable is set because it shows if I call env in the container.

How should I escape the SRC variable so that it is expanded inside the shell run in the docker container?


Solution

  • The reason you're confused is that the quoting issue you have isn't related to make. It's related to the shell.

    As always with writing make recipes you should FIRST ensure you can run the command from the shell prompt and it does what you want. Only after that should you put it in a recipe. In your case suppose you run this at the shell prompt:

    docker run \
        --rm \
        -t \
        --env SRC="/mypath" \
        ubuntu:xenial \
        /bin/bash -c "echo $SRC"
    

    This won't work. Why not? Because, the shell will expand all variables within double-quotes before it invokes the command. This means your docker command actually gets this as arguments:

    docker run \
        --rm \
        -t \
        --env SRC="/mypath" \
        ubuntu:xenial \
        /bin/bash -c "echo "
    

    because the shell expands the $SRC variable, which is empty (it won't be set until docker starts, but this expansion happens by the shell before docker starts).

    You need to use single quotes to avoid having the shell expand your variable:

    docker run \
        --rm \
        -t \
        --env SRC="/mypath" \
        ubuntu:xenial \
        /bin/bash -c 'echo $SRC'
    

    Now you should be able to get your makefile recipe to work as you expect.