带有美元变量的 Docker exec

Ell*_*t B 2 linux bash docker

我正在尝试使用环境变量在 Docker 容器内运行命令,但我无法找出正确的语法。

我可以看到变量设置正确:

$ docker exec -e FOO=bar cfdb72_db_1 env | grep FOO
FOO=bar
Run Code Online (Sandbox Code Playgroud)

我认为双美元符号 ( $$) 在这里可以工作,但打印出一个奇怪的数字。

$ docker exec -e FOO=bar cfdb72_db_1 echo $FOO

$ docker exec -e FOO=bar cfdb72_db_1 echo '$FOO'
$FOO
$ docker exec -e FOO=bar cfdb72_db_1 echo \$FOO
$FOO
$ docker exec -e FOO=bar cfdb72_db_1 echo $$FOO
24136FOO
Run Code Online (Sandbox Code Playgroud)

Kam*_*ski 6

事实

  • docker exec运行可执行文件,而不是 shell 中的命令。
  • 在您的情况下,可执行文件是echo.
  • echo不关心环境变量。当它到达时$FOO,它会打印$FOO

你的尝试解释了

  1. docker exec -e FOO=bar cfdb72_db_1 echo $FOO
    
    Run Code Online (Sandbox Code Playgroud)

    docker是一个命令。exec-eFOO=barcfdb72_db_1echo是命令将获取的命令行参数。$FOO未加引号,因此您当前的 shell 会扩展它。该变量在当前 shell 中不存在(或者可能存在但包含所有空格或空字符串)。"$FOO"将使 shell 在 后恰好传递一个附加参数echo。不加引号$FOO 可以扩展到零个或多个单词;在您的特定情况下,该数字为零。所以就好像你运行:

    docker exec -e FOO=bar cfdb72_db_1 echo
    
    Run Code Online (Sandbox Code Playgroud)

    在容器中运行的命令是sole echo。Soleecho只打印一个换行符。

  2. docker exec -e FOO=bar cfdb72_db_1 echo '$FOO'
    
    Run Code Online (Sandbox Code Playgroud)

    $FOO是单引号引起来的,shell 不会将其视为变量来展开。shell 在将文字$FOO字符串作为参数传递给之前删除引号docker。可执行文件docker接收exec-eFOO=barcfdb72_db_1echo$FOO作为参数。在容器中运行的命令是类似的echo $FOO,但是没有shell可以扩展$FOO。事实上,我不应该写echo $FOO,因为这个字符串不作为必须拆分的单个实体存在。您的 shell 已经识别了原始命令中的单词,并将echo$FOO作为单独的参数传递给了它们docker,从那时起它们被视为某个数组的不同成员。考虑在容器中运行的命令为echo $FOOraterthan echo $FOO。在容器中echo直接运行并按$FOO字面意思接收,因此它会打印$FOO(后跟换行符,因为这是echo默认情况下的工作方式)。

  3. docker exec -e FOO=bar cfdb72_db_1 echo \$FOO
    
    Run Code Online (Sandbox Code Playgroud)

    $被转义后,shell 不会将$FOOin\$FOO视为要展开的变量。$FOOshell 所做的唯一一件事就是在将文字字符串作为参数传递给 之前删除反斜杠docker。其余的事情与上面完全一样。

  4. docker exec -e FOO=bar cfdb72_db_1 echo $$FOO
    
    Run Code Online (Sandbox Code Playgroud)

    $$未加引号,当前 shell 会扩展它。它是一个特殊参数,可扩展为 shell 的十进制进程 ID。显然它24136在你的例子中。展开后就$$FOO变成了24136FOO。在容器中运行的命令就像echo 24136FOO(再次想到echo 24136FOO而不是echo 24136FOO)。实际上echo打印24136FOO(和换行符)。


解决方案

如果你想$FOO扩展,你需要一个可以扩展它的 shell:

docker exec -e FOO=bar cfdb72_db_1 sh -c 'echo "$FOO"'
Run Code Online (Sandbox Code Playgroud)

现在,在容器中运行的命令sh带有参数-cecho "$FOO"

笔记:

  • $FOO当容器内的新 shell 解释代码时,会正确地用双引号引起来。有两个 shell,两个级别的引用。单引号用于当前 shell;双引号用于新外壳。
  • 在大多数 shell 中(以及在 的大多数实现中shecho是内置的。在您的所有示例中echo都是一个独立的可执行文件(/bin/echo或容器内的任何内容)。两者应该(大部分)等效。但一般来说,请记住 shell 中具有某个名称的命令和直接调用的具有相同名称的命令不一定是同一件事。