替换 dockerfile 变量中的字符 - 错误:替换中缺少 ':'

ai2*_*2ys 11 docker dockerfile

在我的 docker 文件中,我为带有点的版本号定义了一个变量,我想将其替换为下划线以供进一步使用。

ARG ABC_VERSION=1.2.3
ARG SOME_OTHER_VARIABLE=/dir_name/abc_${ABC_VERSION//./_}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我收到以下错误。

failed to process "/dir_name/abc_${ABC_VERSION//./_}": missing ':' in substitution
Run Code Online (Sandbox Code Playgroud)

我需要在 dockerfile 中使用“.”多次使用版本号。一次使用“_”,我不喜欢定义两个变量。

有人知道如何解决这个问题吗?


编辑:我想利用该功能来替换字符的实际代码的一部分如下所示。

ARG EXPAT_VERSION=2.1.0
# ...
RUN wget https://github.com/libexpat/libexpat/releases/download/R_${EXPAT_VERSION//./_}/expat-${EXPAT_VERSION}.tar.gz \
    && tar xzf expat-${EXPAT_VERSION}.tar.gz \
    && cp -R expat-${EXPAT_VERSION}/lib ./xmp_sdk/third-party/expat \
    && rm -r expat-${EXPAT_VERSION} && rm expat-${EXPAT_VERSION}.tar.gz
Run Code Online (Sandbox Code Playgroud)

我看到在tensorflow-gpu dockerfiles中使用了类似的东西:

ARG CUDA=10.1
#...
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    cuda-command-line-tools-${CUDA/./-} #...
Run Code Online (Sandbox Code Playgroud)

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/dockerfiles/dockerfiles/devel-gpu.Dockerfile

Eri*_*kMD 15

${parameter/pattern/string}语法实际上是 Bash 功能(参见shell 参数扩展),而不是 POSIX 功能。

\n\n

根据官方文档,Dockerfile指令仅支持:

\n\n
$var\n${var}\n${var:-word} \xe2\x86\x92 if var is not set then word is the result;\n${var:+word} \xe2\x86\x92 if var is set then word is the result, otherwise the empty string\n
Run Code Online (Sandbox Code Playgroud)\n\n

解决方法1

\n\n

所以这个问题没有“直接”的解决方案,但是如果最终在某些 shell 命令(在RUN,ENTRYPOINTCMD指令中)中使用您想要替换的变量,您也可以保留初始值按原样(没有替换),然后稍后替换它?

\n\n

我的意思是,例如以下Dockerfile:

\n\n
FROM debian\n\nARG ABC_VERSION=1.2.3\nENV SOME_OTHER_VARIABLE=/app/${ABC_VERSION}\n\nWORKDIR /app\n\nRUN /bin/bash -c \'touch "${SOME_OTHER_VARIABLE//./_}"\'\n\n# RUN touch "${SOME_OTHER_VARIABLE//./_}"\n# would raise /bin/sh: 1: Bad substitution\n\nCMD ["/bin/bash", "-c", "ls -hal \\"${SOME_OTHER_VARIABLE//./_}\\""]\n
Run Code Online (Sandbox Code Playgroud)\n\n

作为旁白:

\n\n
    \n
  • 我替换ARG SOME_OTHER_VARIABLEENV SOME_OTHER_VARIABLE只是为了能够从 中使用它CMD
  • \n
  • 可以回忆一下,ENTRYPOINT指令CMD应该以 exec 形式 \xe2\x88\x92 \xe2\x88\x92 编写,CMD ["\xe2\x80\xa6", "\xe2\x80\xa6"]而不是以 shell 形式编写(例如,参见该问题:CMD 在 Dockerfile 中的 ENTRYPOINT 之后不运行)。
  • \n
\n\n

解决方法2

\n\n

或者作为替代解决方法,您可能希望将版本号拆分为主要版本号、次要版本号、补丁,以编写类似这样的内容?

\n\n
ARG MAJOR=1\nARG MINOR=2\nARG PATCH=3\nARG ABC_VERSION=$MAJOR.$MINOR.$PATCH\nARG SOME_OTHER_VARIABLE=/dir_name/abc_${MAJOR}_${MINOR}_${PATCH}\n\xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n\n

解决方法 1 的更简洁语法

\n\n

在OP的编辑之后,我想一个问题是我在“解决方法1”中提到的这一行的相对冗长:

\n\n
\xe2\x80\xa6\nRUN /bin/bash -c \'touch "${SOME_OTHER_VARIABLE//./_}"\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了缓解这一问题,Docker 允许用 Bash 替换隐含的 shell(默认情况下sh),Bash 确实支持您感兴趣的 shell 参数扩展。关键点是必须在命令之前编写以下指令RUN(并且该指令是正是OP提到的Dockerfile的一部分):

\n\n
SHELL ["/bin/bash", "-c"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,Dockerfile 变为:

\n\n
\xe2\x80\xa6    \nARG ABC_VERSION=1.2.3\n\nSHELL ["/bin/bash", "-c"]\nRUN touch "/dir_name/abc_${ABC_VERSION//./_}" \\\n  && ls -hal "/dir_name/abc_${ABC_VERSION//./_}"\n
Run Code Online (Sandbox Code Playgroud)\n\n

或利用一些临时环境变量

\n\n
\xe2\x80\xa6    \nARG ABC_VERSION=1.2.3\n\nSHELL ["/bin/bash", "-c"]\nRUN export SOME_OTHER_VARIABLE="/dir_name/abc_${ABC_VERSION//./_}" \\\n  && touch "$SOME_OTHER_VARIABLE" \\\n  && ls -hal "$SOME_OTHER_VARIABLE"\n
Run Code Online (Sandbox Code Playgroud)\n