如何在本地获取我在 Docker 格式的 env 文件中定义的环境变量?

bil*_*ohi 5 bash docker

我已经以 Docker 格式编写了一堆环境变量,但现在我想在该上下文之外使用它们。我怎样才能用一行 bash 来获取它们?


细节

Docker runcompose具有从文件导入一组环境变量的便利工具。该文件具有非常文字的格式。

  1. 该值按原样使用,根本没有修改。例如,如果值被引号包围(通常是 shell 变量的情况),则引号包含在传递的值中

  2. 以 # 开头的行被视为注释并被忽略

  3. 空行也会被忽略。

  4. “如果没有提供 = 并且该变量......在您的本地环境中导出,”docker“将其传递给容器”
  5. 值得庆幸的是,之前的空白=将导致运行失败

所以,例如,这个 env 文件:

# This is a comment, with an = sign, just to mess with us
VAR1=value1
VAR2=value2

USER
VAR3=is going to = trouble
VAR4=this $sign will mess with things
VAR5=var # with what looks like a comment
#VAR7 =would fail
VAR8= but what about this?
VAR9="and this?"
Run Code Online (Sandbox Code Playgroud)

在容器中产生这些环境变量:

user=ubuntu
VAR1=value1
VAR2=value2
VAR3=is going to = trouble
VAR4=this $sign will mess with things
VAR5=var # with what looks like a comment
VAR8= but what about this?
VAR9="and this?"
Run Code Online (Sandbox Code Playgroud)

好的一面是,一旦我知道我在做什么,就很容易预测效果。我所见即所得。但我不认为 bash 能够在没有很多变化的情况下以相同的方式解释这一点。我怎样才能把这个方形的 Docker 钉子放到一个圆形的 Bash 孔里?

bil*_*ohi 3

长话短说:

\n\n
source <(sed -E -e "s/^([^#])/export \\1/" -e "s/=/=\'/" -e "s/(=.*)$/\\1\'/" env.list)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

您可能想要获取一个文件,其内容

\n\n
\n

执行起来就像在命令行中打印它们一样。

\n
\n\n

但什么文件?原始 docker env 文件是不合适的,因为它不会export分配变量以便子进程可以使用它们,并且任何带有空格、引号和其他特殊字符的输入行都会产生不良结果。

\n\n

由于您不想手动编辑该文件,因此可以使用流编辑器将这些行转换为对 bash 更友好的内容。我一开始尝试使用一两个复杂的 Perl 5 正则表达式或某种工具组合来解决这个问题,但我最终决定使用一个sed命令,使用一个简单的正则表达式和两个扩展的正则表达式:

\n\n
sed -E -e "s/^([^#])/export \\1/" -e "s/=/=\'/" -e "s/(=.*)$/\\1\'/" env.list\n
Run Code Online (Sandbox Code Playgroud)\n\n

这有很多作用。

\n\n
    \n
  • 第一个表达式添加export到第一个字符不是 的任何行的前面#。\n\n
      \n
    • 正如所讨论的,这使得变量可用于您在此会话中运行的任何其他内容,这就是您在这里的全部目的。
    • \n
  • \n
  • =第二个表达式只是在一行中的第一个表达式之后插入一个单引号(如果适用)。\n\n
      \n
    • 这将始终包含整个值,而贪婪匹配可能会删除一些 (eg) VAR3,例如
    • \n
  • \n
  • 第三个表达式将第二个引号附加到至少有一个 的任何行=。\n\n
      \n
    • 这里重要的是再次匹配,=这样我们就不会创建不匹配的引号
    • \n
  • \n
\n\n

结果:

\n\n
# This is a comment, with an =\' sign, just to mess with us\'\nexport VAR1=\'value1\'\nexport VAR2=\'value2\'\n\nexport USER\nexport VAR3=\'is going to = trouble\'\nexport VAR4=\'this $sign will mess with things\'\nexport VAR5=\'var # with what looks like a comment\'\n#VAR7 =\'would fail\'\nexport VAR8=\' but what about this?\'\nexport VAR9=\'"and this?"\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

更多细节:

\n\n
    \n
  • 通过将值括在单引号中,您已经\n\n
      \n
    • 防止 bash 假设空格后面的单词是命令
    • \n
    • 适当地将#和所有后续角色带入VAR5
    • \n
    • 阻止了 的求值$sign,如果用双引号括起来,bash 会将其解释为变量
    • \n
  • \n
\n\n

最后,我们将利用进程替换将此流作为文件传递给source,将所有这些都简化为 bash 的一行。

\n\n
source <(sed -E -e "s/^([^#])/export \\1/" -e "s/=/=\'/" -e "s/(=.*)$/\\1\'/" env.list)\n
Run Code Online (Sandbox Code Playgroud)\n\n

等瞧\xc3\xa0!

\n