Docker exec 带美元变量

Docker exec 带美元变量

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

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

$ docker exec -e FOO=bar cfdb72_db_1 env | grep FOO
FOO=bar

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

$ 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

答案1

事实

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

您的尝试解释

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

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

    docker exec -e FOO=bar cfdb72_db_1 echo
    

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

  2. docker exec -e FOO=bar cfdb72_db_1 echo '$FOO'
    

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

  3. docker exec -e FOO=bar cfdb72_db_1 echo \$FOO
    

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

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

    $$不带引号,当前 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"'

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

笔记:

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

答案2

您正在容器中执行 echo 命令。echo 命令不会扩展$,这是 shell 的工作。您还在 shell 中运行 docker 命令,如果您不从该 shell 中转义变量,该命令将扩展变量,因此 docker 甚至看不到$,更不用说容器内的进程了。

要运行 shell 并避免$FOO在 shell 中扩展解析命令docker,您可以/bin/sh在容器内使用命令行上的单引号:

docker exec -e FOO=bar cfdb72_db_1 /bin/sh -c 'echo "$FOO"'

相关内容