docker sh vs bash 变量 ${@} 扩展 - ${@} 在 sh 中不起作用
docker sh vs bash variable ${@} expansion - ${@} doesn't work in sh
这真的很简单:我正在尝试构建一个 docker 图像,其中入口点接收传递的 args。当我使用 bash
shell 时,它起作用了。当我使用 alpine
附带的 sh
时,它不会扩展;我认为这是因为 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", "-c", "./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”一无所知,所以让我们用 echo
语句替换对 gradlew
的调用,以便进行诊断:
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 [=13=] and any remaining argu‐ ments are assigned to the
positional parameters. The assignment to [=13=] sets the name of the
shell, which is used in warning and error messages.
关键短语是第一个参数分配给$0。这
参数 [=28=]
是当前 运行ning 程序的名称,而不是
而不是程序的参数。您需要在 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", "-c", "echo ${@}", "--" ]
如果我 运行 与上面相同的命令,我现在得到:
arg1 arg2
太好了。
我在评论中提到您滥用了 ${@}
变量
因为你没有引用它。你可能认为你是,但是
/bin/sh
您拨打的电话对这些报价一无所知;这
传递给 shell 的命令很简单:
./gradlew ${@}
...${@}
周围没有引号。让我们稍微修改一下脚本
我们可以看到差异;考虑这个脚本:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "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", "-c", "for arg in \"${@}\"; do echo $arg; done", "--" ]
根据上述输入产生:
arg with spaces
second arg
所以你的 ENTRYPOINT
应该是这样的:
ENTRYPOINT [ "sh", "-c", "./gradlew \"${@}\"", "--" ]
这真的很简单:我正在尝试构建一个 docker 图像,其中入口点接收传递的 args。当我使用 bash
shell 时,它起作用了。当我使用 alpine
附带的 sh
时,它不会扩展;我认为这是因为 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", "-c", "./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”一无所知,所以让我们用 echo
语句替换对 gradlew
的调用,以便进行诊断:
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 [=13=] and any remaining argu‐ ments are assigned to the
positional parameters. The assignment to [=13=] sets the name of the
shell, which is used in warning and error messages.
关键短语是第一个参数分配给$0。这
参数 [=28=]
是当前 运行ning 程序的名称,而不是
而不是程序的参数。您需要在 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", "-c", "echo ${@}", "--" ]
如果我 运行 与上面相同的命令,我现在得到:
arg1 arg2
太好了。
我在评论中提到您滥用了 ${@}
变量
因为你没有引用它。你可能认为你是,但是
/bin/sh
您拨打的电话对这些报价一无所知;这
传递给 shell 的命令很简单:
./gradlew ${@}
...${@}
周围没有引号。让我们稍微修改一下脚本
我们可以看到差异;考虑这个脚本:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "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", "-c", "for arg in \"${@}\"; do echo $arg; done", "--" ]
根据上述输入产生:
arg with spaces
second arg
所以你的 ENTRYPOINT
应该是这样的:
ENTRYPOINT [ "sh", "-c", "./gradlew \"${@}\"", "--" ]