It's really straightforward: I am trying to build a docker image where the entrypoint receives the args passed. When I use a bash
shell, it works. When I use sh
which comes with alpine
it doesn't expand; and I think it's because sh
takes no args at all
Is this possible? And, how?
This doesn't work; meaning docker run -it myimage arg1 arg2
doesn't receive arg1 arg2
as the ${@}
requires. I would expect that gradlew
would be invoked as ./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 ${@}" ]
and this does:
FROM gradle
COPY . /home/gradle
RUN ./gradlew -v && ./gradlew dependencies &> /dev/null
ENTRYPOINT [ "bash", "-c", "./gradlew ${@}" ]
When I dig into what sh
really is:
/bin # which sh
/bin/sh
/bin # ls -al /bin/sh
lrwxrwxrwx 1 root root 12 May 9 2019 /bin/sh -> /bin/busybox
I don't know anything about "gradle", so let's replace your call to gradlew
with an echo
statement in order to diagnose things:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "echo ${@}" ]
If I build an image named cbtest
and run it like this:
docker run --rm cbtest arg1 arg2
I get as output:
arg2
Which means it's mostly working, except as I noted in the comments you're losing your first argument. If we take a look at the bash(1)
man page, we find:
-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.
The key phrase is the first argument is assigned to $0. The
argument $0
is the name of the currently running program, rather
than an argument to the program. You need to add a --
to your sh
command line to indicate that it should stop trying to parse arguments
and just pass everything as parameters to the called script. Again from the man page:
-- 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 --.
This gives us:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "echo ${@}", "--" ]
If I run the same command as above, I now get:
arg1 arg2
So that's great.
I mentioned in the comments that you're misusing the ${@}
variable
because you're not quoting it. You might think you are, but the
/bin/sh
you're calling doesn't know anything about those quotes; the
command passed to the shell is simply:
./gradlew ${@}
...with no quotes around ${@}
. Let's modify the script slightly so
that we can see the difference; consider this script:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "for arg in ${@}; do echo $arg; done", "--" ]
If I run the image like this:
docker run --rm cbtest "arg with spaces" "second arg"
I get as output:
arg
with
spaces
second
arg
As you can see, the script is seeing five arguments rather than two. We can fix that with proper quoting:
FROM openjdk:8u212-jre-alpine
ENTRYPOINT [ "sh", "-c", "for arg in \"${@}\"; do echo $arg; done", "--" ]
Which given the above input produces:
arg with spaces
second arg
So your ENTRYPOINT
should probably look like this:
ENTRYPOINT [ "sh", "-c", "./gradlew \"${@}\"", "--" ]