docker容器中传递的环境变量的可见性 - 误解

docker容器中传递的环境变量的可见性 - 误解

让我们看下面的例子:

[user@user~]$ sudo docker run -d -e XYZ=123 ubuntu sleep 10000
2543e7235fa9
[user@user~]$ sudo docker exec 2543e7235fa9 echo test
test
[user@user~]$ sudo docker exec 2543e7235fa9 echo $XYZ
<empty row>      
[user@user~]$ sudo docker exec -it 2543e7235fa9 bash
root@2543e7235fa9:/# echo $XYZ
123

为什么我得到<empty row>而不是123?为什么执行并进入 bash 后我能够看到XYZ=123

答案1

您在这里缺少的两件事是:

  1. docker exec ... <command>默认情况下不在<command>shell 中运行,它只是<command>在没有 shell 的容器中运行。

    如果您想在非交互式 shell 中运行 docker 中的命令,请使用:

    docker exec <container> bash -c '<command>'
    

    如果<command>有多个单词,则需要用单引号或双引号将整个命令传递给bash -c.

    例如sudo docker exec 2543e7235fa9 bash -c 'echo $XYZ'

 

  1. 当你这样做时,有两个 shell 很重要:

    • 您正在运行的 shell sudo docker exec ...(称为“Shell A”)
    • 在容器内运行的 shell(称为“Shell B”)。

     

    如果你在 shell A 中反斜杠转义或单引号,$然后 shell A 将插入它自己的值$XYZ(即使它没有值,也会返回一个空字符串)。

    因此,如果XYZ=5在 Shell A 中,那么您的sudo docker exec 2543e7235fa9 echo $XYZ与相同exec 2543e7235fa9 echo 5(并且不会有 shell B 因为您没有告诉 docker to run bash -c ...)。

    如果你转义或单引号$,然后将其按原样传递给 shell B,并且 shell B 为 插入其值$XYZ

换句话说,使用:

sudo docker exec 2543e7235fa9 bash -c 'echo $XYZ'

或者

sudo docker exec 2543e7235fa9 bash -c "echo \$XYZ"

在我看来,单引号形式更容易理解它在做什么以及大多数时候你应该使用什么。单引号内不会发生变量插值,因此命令的传递方式与 shell B 完全相同。

当您需要将变量从 shell A 传递到 shell B 时,双引号形式非常有用。如果您还需要传递文字$,则应使用反斜杠转义。例如,让 shell B 回显 shell A$ABC和它自己的$XYZ

sudo docker exec 2543e7235fa9 bash -c "echo $ABC \$XYZ"

如果 shell A$ABC等于123 10,shell B$XYZ等于 123,那么将输出:

10 123

注意:除非$XYZ在 shell B 的启动文件之一中定义,或者docker run -e XYZ=123如您在示例中使用的那样(或使用-env-file),否则它将没有值。

答案2

因为$XYZ它会被运行命令的 shell 扩展docker exec。您需要引用它才能将$XYZ字符串放入其中。

sudo docker exec ... echo \$XYZ

确实存在一个误解 - 什么是参数以及它们在 shell 中的行为方式。当你跑步时

any-command $XYZ

从来any-command没有见过$XYZ。您的 shell 会将其替换为该参数(在该 shell 中)具有的任何值。由于您没有指定参数XYZ或者参数为空,因此您提交到 shell 的实际命令行是

sudo docker exec 2543e7235fa9 echo

相关内容