docker - 替换 dockerfile 变量中的字符 - 错误 : missing ':' in substitution

标签 docker dockerfile

在我的 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 命令中使用(在 RUNENTRYPOINTCMD 指令中),你也可以保留初始值(没有替换),然后再替换它?

例如,我的意思是以下 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 使用它。
  • 可以回想一下,ENTRYPOINTCMD 指令应该以 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/

    相关文章:

    linux - Arch linux [Armv7] docker 安装

    docker - 使用 docker-compose.yml 未在 docker 容器中设置环境变量

    curl - OpenShift 3.1 - 防止 Docker 缓存 curl 资源

    macos - Docker 填满 macOS 上的存储空间

    docker - 在 GoLang Docker SDK 中为卷定义挂载点

    java - Docker 构建无法找到 COPY 命令的源文件夹

    docker - 在Docker中添加主机时如何修复只读错误?

    Redis Docker 连接被拒绝

    docker - 如何在Visual Studio代码中将一种文件类型与另一种文件类型关联?

    docker - 我需要隐藏 Jenkins 日志中的参数