Kevin
Kevin

Reputation: 139

Docker Run Command - Why does "docker run <image ID> echo 'foo'" work, but /bin/sh -c echo 'foo' doesn't? They should be equivalent

With a default entrypoint of /bin/sh -c, I'd expect to see docker run <image ID> echo 'foo' result in /bin/sh -c echo 'foo' execute which does not print foo (foo is an arg for sh here, not echo).

However, it seems to run as if its quoted/passed in as a single arg to sh. What is the reason for this?

The only reason I can think of is that docker run command(s) are parsed as a single command and handed to /bin/sh -c as a single item

Upvotes: 1

Views: 767

Answers (1)

David Maze
David Maze

Reputation: 158908

The sh -c option takes a single argument, which is parsed and executed as a shell command. If that command has multiple words, you need to quote it so it gets passed as a single argument.

This isn't Docker-specific and you can see it in a local shell:

$ echo 'foo'
foo
$ /bin/sh -c echo 'foo'

$ /bin/sh -c "echo 'foo'"
foo

If there are additional parameters, the sh -c command can see them as positional parameters, starting with $0.

$ sh -c 'echo "$2"' foo bar baz quux
baz

In a more Docker-specific context, you can see the same behavior using this as a docker run command

$ docker run --rm busybox sh -c 'echo "$2"' foo bar baz
baz

In a Dockerfile, RUN, CMD, and ENTRYPOINT will automatically add the sh -c wrapper so you don't need to explicitly specify it.

# same:
CMD ls && exec main_program
CMD ["/bin/sh", "-c", "ls && exec main_program"]

# unnecessary extra sh -c:
CMD sh -c 'ls && exec main_program'
CMD ["/bin/sh", "-c", "main_program"] # without redirects, environment variables, ...

You only need the explicit sh -c if you have a complex command as a docker run or Compose command: override command.

Upvotes: 3

Related Questions