【问题标题】:Generating parameters for `docker run` through command expansion from .env files通过 .env 文件的命令扩展为 `docker run` 生成参数
【发布时间】:2020-05-22 20:47:16
【问题描述】:

我在以相对通用的方式将一些环境参数传递给docker run 时遇到了一些问题。

我们的第一次迭代是通过以下几行将.env 文件加载到环境中:

set -o allexport;
. "${PROJECT_DIR}/.env";
set +o allexport;

然后手动键入--env VARNAME=$VARNAME 作为docker run 命令的选项。但是当你有几十个变量时,这可能会很烦人。

然后我们尝试使用 --env-file .env 传递文件,它似乎可以工作,但它没有,因为它不能很好地与变量值周围的引号一起使用。

这是我开始做疯狂/丑陋事情的地方。基本的想法是做这样的事情:

set_docker_parameters()
{
    grep -v '^$' "${PROJECT_DIR}/.env" | while IFS= read -r LINE; do
        printf " -e %s" "${LINE}"
    done
}

docker run $(set_docker_parameters) --rm image:label command

解析的行类似于VARIABLE="value"VARIABLE='value'VARIABLE=value。空行被管道grep 丢弃。

但是docker run 一直抱怨没有被正确调用。当我扩展set_docker_parameters 的结果时,我得到了我所期望的结果,当我复制它的结果并替换$(set_docker_parameters) 时,docker run 也按预期工作,完美无缺。

知道我在这里做错了什么吗?

非常感谢!

P.S.:我正在尝试使我的脚本 100% 与 POSIX 兼容,因此我更喜欢任何不依赖 Bash 特定功能的解决方案。

【问题讨论】:

  • 您的最终方法不适用于任何包含空格的变量。使用数组而不是字符串。
  • @jordanm 嗯.. 我检查了一下,当我在任何变量中没有空格时它确实有效。您有什么好的参考资料可以让我了解如何使用“数组”吗?
  • 我看到 POSIX 规范中不存在数组,它们真的是解决该问题的唯一方法吗?我认为可能有一些不涉及复制粘贴变量定义的解决方法。
  • FAQ 中有一个 POSIX 示例。 POSIX shell 可以模拟带有位置参数的数组。

标签: bash shell docker sh posix


【解决方案1】:

基于@jordanm 的 cmets,我设计了以下解决方案:

docker_run_wrapper()
{
    # That's not ideal, but in any case it's not directly related to the question.
    cmd=$1

    set --; # Unset all positional arguments ($@ will be emptied)

    # We don't have arrays (we want to be POSIX compatible), so we'll
    # use $@ as a sort of substitute, appending new values to it.
    grep -v '^$' "${PROJECT_DIR}/.env" | while IFS= read -r LINE; do
        set -- "$@" "--env";
        set -- "$@" "${LINE}";
    done

    # We use $@ in a clearly non-standard way, just to expand the values
    # coming from the .env file.
    docker run "$@" "image:label" /bin/sh -c "${cmd}";
}

再一次,这不是我为特定用例编写的代码,而是显示基本思想的简化。如果你可以依赖 Bash,那么它可能会更干净,通过不重载 $@ 并使用数组。

【讨论】:

  • 你不需要grep;只需将[ -z "$LINE" ] && continue 作为while 循环的第一行。您现在拥有的东西不应该工作,因为您在管道创建的子shell中设置位置参数,而不是执行函数的shell。
  • 这也不是“非标准”;这正是为什么set 命令允许您以这种方式构造$@ 的值,以及为什么"$@" 的行为方式(与"$*" 相比)。
  • grep 在任何情况下都不应该创建子shell(据我所知,它没有)。如果我正确理解 shell 的工作原理,要执行的第一个命令是 while,它开始监听管道,然后启动 grep,写入管道。
  • 除此之外,我玩了一下它,将整个文件重定向到循环while [...]; do [...]; done < ".env"(并测试循环内的空行),代码又出现了错误由于我不明白的原因,所以我想我仍然需要了解一些关于这件事的额外细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-14
  • 2019-04-03
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多