How to pass arguments to Shell Script through docker run
I am new to the docker world. I have to invoke a shell script that takes command line arguments through a docker container. Ex: My shell script looks like:
#!bin/bash
echo $1
Dockerfile looks like this:
FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh
I am not sure how to pass the arguments while running the container
with this script in file.sh
#!/bin/bash
echo Your container args are: "$@"
and this Dockerfile
FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]
you should be able to:
% docker build -t test .
% docker run test hello world
Your container args are: hello world
Use the same file.sh
#!/bin/bash
echo $1
Build the image using the existing Dockerfile:
docker build -t test .
Run the image with arguments abc
or xyz
or something else.
docker run -ti --rm test /file.sh abc
docker run -ti --rm test /file.sh xyz
With Docker, the proper way to pass this sort of information is through environment variables.
So with the same Dockerfile, change the script to
#!/bin/bash
echo $FOO
After building, use the following docker command:
docker run -e FOO="hello world!" test
There are a few things interacting here:
docker run your_image arg1 arg2
will replace the value ofCMD
witharg1 arg2
. That's a full replacement of the CMD, not appending more values to it. This is why you often seedocker run some_image /bin/bash
to run a bash shell in the container.When you have both an ENTRYPOINT and a CMD value defined, docker starts the container by concatenating the two and running that concatenated command. So if you define your entrypoint to be
file.sh
, you can now run the container with additional args that will be passed as args tofile.sh
.Entrypoints and Commands in docker have two syntaxes, a string syntax that will launch a shell, and a json syntax that will perform an exec. The shell is useful to handle things like IO redirection, chaining multiple commands together (with things like
&&
), variable substitution, etc. However, that shell gets in the way with signal handling (if you've ever seen a 10 second delay to stop a container, this is often the cause) and with concatenating an entrypoint and command together. If you define your entrypoint as a string, it would run/bin/sh -c "file.sh"
, which alone is fine. But if you have a command defined as a string too, you'll see something like/bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"
as the command being launched inside your container, not so good. See the table here for more on how these two options interactThe shell
-c
option only takes a single argument. Everything after that would get passed as$1
,$2
, etc, to that single argument, but not into an embedded shell script unless you explicitly passed the args. I.e./bin/sh -c "file.sh $1 $2" "arg1" "arg2"
would work, but/bin/sh -c "file.sh" "arg1" "arg2"
would not sincefile.sh
would be called with no args.
Putting that all together, the common design is:
FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]
And you then run that with:
docker run your_image arg1 arg2
There's a fair bit more detail on this at:
- https://docs.docker.com/engine/reference/run/#cmd-default-command-or-options
- https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example