在传递给 docker run 命令的变量中转义 $

Mak*_*s_F 1 makefile gnu-make variable-expansion docker

从 makefile 执行命令时,我不知道如何转义美元符号以访问在 docker 环境中定义的变量。

这是我的设置的最小表示,我正在尝试回应 /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 ))
Run Code Online (Sandbox Code Playgroud)

输出是

$ 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
Run Code Online (Sandbox Code Playgroud)

我知道环境变量已设置,因为它会显示我是否env在容器中调用。

我应该如何转义 SRC 变量,以便它在 docker 容器中运行的 shell 内展开?

Mad*_*ist 5

您感到困惑的原因是您遇到的引用问题与 make 无关。它与外壳有关。

与编写 make recipe 一样,您应该首先确保可以从 shell 提示符运行命令,并且它可以执行您想要的操作。只有在那之后你才应该把它放在食谱中。在您的情况下,假设您在 shell 提示符下运行它:

docker run \
    --rm \
    -t \
    --env SRC="/mypath" \
    ubuntu:xenial \
    /bin/bash -c "echo $SRC"
Run Code Online (Sandbox Code Playgroud)

这行不通。为什么不?因为,shell 会在调用命令之前扩展双引号内的所有变量。这意味着您的 docker 命令实际上将其作为参数:

docker run \
    --rm \
    -t \
    --env SRC="/mypath" \
    ubuntu:xenial \
    /bin/bash -c "echo "
Run Code Online (Sandbox Code Playgroud)

因为 shell 扩展了$SRC变量,它是空的(它不会在 docker 启动之前设置,但是这个扩展在 docker 启动之前由 shell 发生)。

您需要使用单引号来避免让 shell 扩展您的变量:

docker run \
    --rm \
    -t \
    --env SRC="/mypath" \
    ubuntu:xenial \
    /bin/bash -c 'echo $SRC'
Run Code Online (Sandbox Code Playgroud)

现在您应该能够让您的 makefile 配方按预期工作。