Home > Enterprise >  Difference between RUN bash -c and open form of RUN
Difference between RUN bash -c and open form of RUN

Time:04-30

Some Dockerfiles have

RUN bash -c "apt-get update -qq && ... \"

while others write without quotes like

RUN apt-get update -qq && ... \

What is the difference between these variants? Is one of them more preferable over another one?

CodePudding user response:

You should just write RUN apt-get update ... without manually inserting a sh -c wrapper.

The RUN, CMD, and ENTRYPOINT directives all share the same syntax. It's best documented for ENTRYPOINT but all three commands work the same way. There are two ways to write commands for them: you can either provide a specific set of command words as a JSON array (exec form), or you can write a string and Docker will automatically wrap it sh -c (shell form). For example:

# Create a directory with a space in its name
RUN mkdir "a directory"

# JSON-array form: each array element is a shell word
RUN ["ls", "-ld", "a directory"]

# String form: Docker provides a shell, so these two are equivalent
RUN ls -ld 'a directory'
RUN ["/bin/sh", "-c", "ls -ld 'a directory'"]

This makes your first form redundant: if you RUN bash -c '...', it's a string, and Docker automatically wraps it in sh -c. So you get in effect

# RUN bash -c '...'
RUN ["/bin/sh", "-c", "bash -c '...'"]

GNU bash has a number of extensions that are not POSIX-standard syntax and it's possible to run into trouble with these, particularly on an Alpine-based image where /bin/sh is a minimal shell from the BusyBox toolset. I could see this as an attempt to force a shell command to run using bash rather than the default shell. For most things that appear in Dockerfiles, they won't usually be so complex that they can't be easily rewritten in standard syntax.

# Needs bash for the non-standard `source` syntax
RUN bash -c 'source ./venv/bin/activate && pip list'

# But you can use the standard `.` instead
RUN . ./venv/bin/activate && pip list

If you must have bash interpreting RUN lines then I'd suggest using the SHELL directive to change the command that's used to interpret bare strings.

Style-wise, I also occasionally see JSON-array syntax that begins with an explicit CMD ["/bin/sh", "-c", "..."]. There's no reason to write this out; it's shorter and no less clear to use the string form.

  • Related