docker sh vs bash 变量 ${@} 扩展 - ${@} 在 sh 中不起作用

问题描述

这真的很简单:我正在尝试构建一个 docker 映像,其中入口点接收传递的 args。当我使用 bash shell 时,它可以工作。当我使用 sh 附带的 alpine 时,它不会扩展;我认为这是因为 sh 根本不需要参数

这可能吗?还有,怎么样?

这不起作用;意味着 docker run -it myimage arg1 arg2 不会像 arg1 arg2 要求的那样收到 ${@}。我希望 gradlew 会被调用./gradlew arg1 arg2

FROM openjdk:8u212-jre-alpine
RUN apk add --no-cache jq openjdk8 python3 \
    && pip3 install --upgrade pip && pip3 install yq
copY . /root
workdir /root
RUN ./gradlew dependencies &> /dev/null
ENTRYPOINT [ "sh","-c","./gradlew ${@}" ]

这样做:

FROM gradle
copY . /home/gradle
RUN ./gradlew -v && ./gradlew dependencies &> /dev/null
ENTRYPOINT [ "bash","./gradlew ${@}" ]

当我深入了解 sh 的真正含义时:

/bin # which sh
/bin/sh
/bin # ls -al /bin/sh
lrwxrwxrwx    1 root     root            12 May  9  2019 /bin/sh -> /bin/busyBox

解决方法

我对“gradle”一无所知,因此让我们将您对 gradlew 的调用替换为 echo 语句以进行诊断:

FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh","-c","echo ${@}" ]

如果我构建一个名为 cbtest 的映像并像这样运行它:

docker run --rm cbtest arg1 arg2

我得到的输出:

arg2

这意味着它主要是有效的,除非我在评论中指出你失去了你的第一个论点。如果我们查看 bash(1) 手册页,我们会发现:

-c  If  the  -c option is present,then commands are read from the
    first non-option argument  command_string.   If  there  are
    arguments  after  the  command_string,the  first  argument is
    assigned to $0 and any remaining argu‐ ments are assigned to the
    positional parameters.  The assignment to $0  sets the name of the
    shell,which is used in warning and error messages.

关键短语是第一个参数分配给 $0。这 参数 $0 是当前正在运行的程序的名称,而不是 而不是程序的参数。您需要将 -- 添加到您的 sh 指示它应该停止尝试解析参数的命令行 并将所有内容作为参数传递给被调用的脚本。再次来自手册页:

--  A -- signals the end of options and disables further option
    processing.  Any arguments  after the -- are treated as filenames
    and arguments.  An argument of - is equivalent to --.

这给了我们:

FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh","echo ${@}","--" ]

如果我运行与上面相同的命令,我现在得到:

arg1 arg2

那太好了。

我在评论中提到您滥用了 ${@} 变量 因为你没有引用它。你可能认为你是,但是 /bin/sh 你调用的对这些引用一无所知;这 传递给shell的命令很简单:

./gradlew ${@}

...${@} 周围没有引号。让我们稍微修改一下脚本 我们可以看到差异;考虑这个脚本:

FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh","for arg in ${@}; do echo $arg; done","--" ]

如果我像这样运行图像:

docker run --rm cbtest "arg with spaces" "second arg"

我得到的输出:

arg
with
spaces
second
arg

如您所见,脚本看到的是五个参数而不是两个。 我们可以通过适当的引用来解决这个问题:

FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh","for arg in \"${@}\"; do echo $arg; done","--" ]

给定以上输入产生的结果:

arg with spaces
second arg

所以您的 ENTRYPOINT 应该看起来像这样:

ENTRYPOINT [ "sh","./gradlew \"${@}\"","--" ]