【问题标题】:How to write commands with multiple lines in Dockerfile while preserving the new lines?如何在 Dockerfile 中编写多行命令,同时保留新行?
【发布时间】:2016-01-31 01:41:21
【问题描述】:

我想在 Dockerfile 中编写以下 RUN 命令。但是,docker 并没有保留新行。

RUN echo "[repo] \
name            = YUM Repository \
baseurl         = https://example.com/packages/ \
enabled         = 1 \
gpgcheck        = 0" > /etc/yum.repos.d/Repo.repoxyz

我知道每行末尾的\ 会转义新行。但是,有什么办法可以写多行来保留新行?

【问题讨论】:

  • 您使用的是非 *nix 平台吗?因为这在 Linux 上对我来说很好。
  • @user,我使用的是 Linux。

标签: docker dockerfile


【解决方案1】:

您可以在$'...' 中使用所谓的“ANSI-C 引用”。 It was originally a ksh93 feature 但它现在可以在 bash、zsh、mksh、FreeBSD shbusybox 的 ash 中使用(但仅当它使用 ENABLE_ASH_BASH_COMPAT 编译时)。

作为RUN uses /bin/sh as shell by default,您需要先使用 SHELL 指令切换到 bash 之类的东西。

$' 开始您的命令,以' 结束并使用\n\ 作为换行符,如下所示:

SHELL ["/bin/bash", "-c"]

RUN echo $'[repo] \n\
name            = YUM Repository \n\
baseurl         = https://example.com/packages/ \n\
enabled         = 1 \n\
gpgcheck        = 0' > /etc/yum.repos.d/Repo.repoxyz

【讨论】:

  • 是 bash 语法。有关更多信息,请参阅此问题:stackoverflow.com/a/11966402/1395437
  • 请解释一下你在做什么,不要只是放弃一个不透明的解决方案
  • 请注意:$' ... \n\ 技术依赖于 docker RUN 使用的 shell 是 bash。在某些系统(例如 Ubuntu)上,shell RUN 使用的是 /bin/sh,它通常是指向 dash 的链接,而不是 bash,并且不理解 $' 语法。
  • 正如@Anon 所说,如果在 bash 以外的任何地方运行,这将不起作用。 (也不适用于Oh My Zsh
  • @Anon 很好,它在使用 shell 的 Alpine linux(目前我在 3.10.2)中工作。
【解决方案2】:

我使用了printf。使用\n将所有文本写在一行中。

执行:

RUN printf 'example \ntext \nhere' >> example.txt

插入:

example
text
here

example.txt

【讨论】:

    【解决方案3】:

    你可以使用:

    RUN echo -e "\
    [repo] \n\
    name            = YUM Repository \n\
    baseurl         = https://example.com/packages/ \n\
    enabled         = 1 \n\
    gpgcheck        = 0\
    " > /etc/yum.repos.d/Repo.repoxyz
    

    这样您就可以快速检查文件内容。您只需要注意,您需要以\ 结束每一行并在需要时插入\n

    【讨论】:

    • 这需要echo -e 来解释\n
    • 使用-e 选项给了我一个意想不到的行为。该选项不会被解释为这样,而是作为要打印的文本的一部分。
    【解决方案4】:

    可能对你有帮助 (https://github.com/jen-soft/pydocker)

    [Dockerfile.py]

    from pydocker import DockerFile  # sudo pip install -U pydocker
    
    d = DockerFile(base_img='debian:8.2', name='jen-soft/custom-debian:8.2')
    
    d.RUN_bash_script('/opt/set_repo.sh', r'''
    cat >/etc/apt/sources.list <<EOL
    deb     http://security.debian.org/ jessie/updates main
    deb-src http://security.debian.org/ jessie/updates main
    EOL
    apt-get clean && apt-get update
    ''')
    
    d.EXPOSE = 80
    d.WORKDIR = '/opt'
    d.CMD = ["python", "--version"]
    
    # d.generate_files()
    d.build_img()
    
    
    # sudo wget -qO- https://get.docker.com/ | sh
    
    python Dockerfile.py
    docker images
    

    【讨论】:

      【解决方案5】:

      我最终使用了上面列出的示例的组合,因为新行 \n 不适用于 echo

      RUN printf 'example \n\
      text \n\
      here' >> example.txt
      

      正如预期的那样,它会产生以下内容:

      example
      text
      here
      

      【讨论】:

      • 您的回答与 CTodea 的回答有何不同?
      • @TheGodfather 这是一个多行示例。也可以更好地回答原始问题。
      【解决方案6】:

      您可以多次执行 RUN 来完成您的文件:

      RUN echo "[repo]" >> /etc/yum.repos.d/Repo.repoxyz
      RUN echo "name            = YUM Repository" >> /etc/yum.repos.d/Repo.repoxyz
      RUN echo "baseurl         = https://example.com/packages/" >> /etc/yum.repos.d/Repo.repoxyz
      RUN echo "enabled         = 1" >> /etc/yum.repos.d/Repo.repoxyz
      RUN echo "gpgcheck        = 0" >> /etc/yum.repos.d/Repo.repoxyz
      

      这可能不是最佳解决方案,因为它会为每个 RUN 命令创建一个新层。尽管如此,每一层都将与您所做的更改一样大,在这种情况下,它按字节顺序排列(第一个 RUN 层应该是 7 字节)。

      此解决方案的好处是它适用于所有 shell。

      【讨论】:

      • 最好将这些命令与&amp;&amp; 连接起来,以实现更好的缓存、减少日志记录并加快Dockerfile 构建时间
      • 此解决方案为您的图像添加了太多层,这将增加您的构建时间。
      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 2015-11-11
      • 1970-01-01
      • 2012-08-30
      • 2018-11-22
      相关资源
      最近更新 更多