-1

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
Christian Bongiorno
  • 5,150
  • 3
  • 38
  • 76
  • 1
    `it works` what "works" and how and how do you check it? `&>` is a bash extension. – KamilCuk Feb 03 '21 at 22:04
  • Often `sh` is an alias to `bash` or `dash`. I'd check what the real shell is, or specify what shell you want in `ENTRYPOINT` and avoid any guessing there. – Robert Feb 03 '21 at 22:18
  • updated to reflect your comment @Robert – Christian Bongiorno Feb 03 '21 at 22:40
  • 1
    Can you respond to @KamilCuk's comment? What does "doesn't work" mean? Also note that in both versions you are misusing the `$@` variable (which, when unquoted, is identical to `$*`), and the way you've written things your script will lose its first argument (see the documentation for `-c` in the `bash(1)` man page). – larsks Feb 03 '21 at 22:42
  • @larsks I have answered hist question as well. And, the `${@}` is quoted along with `"gradlew"` – Christian Bongiorno Feb 03 '21 at 22:59
  • @ChristianBongiorno, JSON quoting does not substitute for shell quoting. It would need to be `["bash", "-c", "./gradlew \"$@\""]` for the `$@` to be quoted from the shell's perspective. (You could use `"./gradlew \"${@}\""` but there's no point whatsoever; the extra `{}`s buy you no advantage at all). – Charles Duffy Feb 04 '21 at 00:04
  • ...that said, I don't know why you'd involve bash in this in any whatsoever, instead of just running `ENTRYPOINT [ "./gradlew" ]` – Charles Duffy Feb 04 '21 at 00:06
  • @CharlesDuffy - yup, I discovered that and changed it (re gradlew). – Christian Bongiorno Feb 04 '21 at 20:53

1 Answers1

3

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 \"${@}\"", "--" ]
larsks
  • 277,717
  • 41
  • 399
  • 399