我正在尝试使用环境变量在 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)
docker exec
运行可执行文件,而不是 shell 中的命令。echo
.echo
不关心环境变量。当它到达时$FOO
,它会打印$FOO
。docker exec -e FOO=bar cfdb72_db_1 echo $FOO
Run Code Online (Sandbox Code Playgroud)
docker
是一个命令。exec
、-e
、FOO=bar
、cfdb72_db_1
和echo
是命令将获取的命令行参数。$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
只打印一个换行符。
docker exec -e FOO=bar cfdb72_db_1 echo '$FOO'
Run Code Online (Sandbox Code Playgroud)
$FOO
是单引号引起来的,shell 不会将其视为变量来展开。shell 在将文字$FOO
字符串作为参数传递给之前删除引号docker
。可执行文件docker
接收exec
、-e
、FOO=bar
、cfdb72_db_1
、echo
和$FOO
作为参数。在容器中运行的命令是类似的echo $FOO
,但是没有shell可以扩展$FOO
。事实上,我不应该写echo $FOO
,因为这个字符串不作为必须拆分的单个实体存在。您的 shell 已经识别了原始命令中的单词,并将echo
和$FOO
作为单独的参数传递给了它们docker
,从那时起它们被视为某个数组的不同成员。考虑在容器中运行的命令为echo
$FOO
raterthan echo $FOO
。在容器中echo
直接运行并按$FOO
字面意思接收,因此它会打印$FOO
(后跟换行符,因为这是echo
默认情况下的工作方式)。
docker exec -e FOO=bar cfdb72_db_1 echo \$FOO
Run Code Online (Sandbox Code Playgroud)
$
被转义后,shell 不会将$FOO
in\$FOO
视为要展开的变量。$FOO
shell 所做的唯一一件事就是在将文字字符串作为参数传递给 之前删除反斜杠docker
。其余的事情与上面完全一样。
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
带有参数-c
和echo "$FOO"
。
笔记:
$FOO
当容器内的新 shell 解释代码时,会正确地用双引号引起来。有两个 shell,两个级别的引用。单引号用于当前 shell;双引号用于新外壳。sh
)echo
是内置的。在您的所有示例中echo
都是一个独立的可执行文件(/bin/echo
或容器内的任何内容)。两者应该(大部分)等效。但一般来说,请记住 shell 中具有某个名称的命令和直接调用的具有相同名称的命令不一定是同一件事。