在我的 docker 文件中,我为带有点的版本号定义了一个变量,我想用下划线替换它以供进一步使用。
ARG ABC_VERSION=1.2.3
ARG SOME_OTHER_VARIABLE=/dir_name/abc_${ABC_VERSION//./_}
不幸的是,我收到以下错误。
failed to process "/dir_name/abc_${ABC_VERSION//./_}": missing ':' in substitution
我需要多次在 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
我看到在 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/./-} #...
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/dockerfiles/dockerfiles/devel-gpu.Dockerfile
最佳答案
${parameter/pattern/string}
语法实际上是 Bash 功能(参见 shell parameter expansion ),而不是 POSIX 功能。
根据 the official documentation ,Dockerfile 指令仅支持:
$var
${var}
${var:-word} → if var is not set then word is the result;
${var:+word} → if var is set then word is the result, otherwise the empty string
解决方法 1
所以这个问题没有一个“直接”的解决方案,但是如果你想要替换的变量最终会在一些 shell 命令中使用(在
RUN
、 ENTRYPOINT
或 CMD
指令中),你也可以保留初始值(没有替换),然后再替换它?例如,我的意思是以下 Dockerfile:
FROM debian
ARG ABC_VERSION=1.2.3
ENV SOME_OTHER_VARIABLE=/app/${ABC_VERSION}
WORKDIR /app
RUN /bin/bash -c 'touch "${SOME_OTHER_VARIABLE//./_}"'
# RUN touch "${SOME_OTHER_VARIABLE//./_}"
# would raise /bin/sh: 1: Bad substitution
CMD ["/bin/bash", "-c", "ls -hal \"${SOME_OTHER_VARIABLE//./_}\""]
作为旁白:
ARG SOME_OTHER_VARIABLE
替换了 ENV SOME_OTHER_VARIABLE
只是为了能够从 CMD
使用它。 ENTRYPOINT
和 CMD
指令应该以 exec 形式 - CMD ["…", "…"]
- 而不是以 shell 形式编写(参见例如那个问题: CMD doesn't run after ENTRYPOINT in Dockerfile )。 解决方法 2
或者作为替代的解决方法,您可能希望将您的版本号拆分为主要、次要、补丁,以编写类似的内容?
ARG MAJOR=1
ARG MINOR=2
ARG PATCH=3
ARG ABC_VERSION=$MAJOR.$MINOR.$PATCH
ARG SOME_OTHER_VARIABLE=/dir_name/abc_${MAJOR}_${MINOR}_${PATCH}
…
解决方法 1 的更简洁的语法
在 OP 的编辑之后,我想一个问题是我在“解决方法 1”中提到的这一行的相对冗长:
…
RUN /bin/bash -c 'touch "${SOME_OTHER_VARIABLE//./_}"'
为了缓解这种情况,Docker 允许用 Bash 替换隐含的 shell(默认为
sh
),它确实支持您感兴趣的 shell 参数扩展。关键点是必须在 RUN
命令之前编写以下指令(和这正是 part of the Dockerfile the OP mentioned ):SHELL ["/bin/bash", "-c"]
因此,Dockerfile 变为:
…
ARG ABC_VERSION=1.2.3
SHELL ["/bin/bash", "-c"]
RUN touch "/dir_name/abc_${ABC_VERSION//./_}" \
&& ls -hal "/dir_name/abc_${ABC_VERSION//./_}"
或者利用一些 临时环境变量 :
…
ARG ABC_VERSION=1.2.3
SHELL ["/bin/bash", "-c"]
RUN export SOME_OTHER_VARIABLE="/dir_name/abc_${ABC_VERSION//./_}" \
&& touch "$SOME_OTHER_VARIABLE" \
&& ls -hal "$SOME_OTHER_VARIABLE"
关于docker - 替换 dockerfile 变量中的字符 - 错误 : missing ':' in substitution,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61827259/