• Modern UX

    Edit and navigate faster in the terminal with Warp's IDE-like input editor.

  • Warp AI

    AI suggests what commands to run and learns from your documentation.

  • Agent Mode

    Delegate tasks to AI and use natural language on the command line.

  • Warp Drive

    Save and share interactive notebooks, workflows, and environment variables.

  • All Features

Run a Shell Script in a Dockerfile

Thumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell Wilson
Preston Tunnell Wilson

Preston Tunnell Wilson

Senior Software Engineer, InStride Health

Published: 12/1/2023

About Terminus

The Short Answer

COPY the shell script that you want to run into the container and then either RUN it if you want to execute it while you build the container:

Thumbnail for Thumbnail for Thumbnail for Thumbnail for

Or use it in a CMD instruction if the script executes the main functionality of your Docker container:

Thumbnail for Thumbnail for Thumbnail for Thumbnail for

When might you want to run a shell script in your Dockerfile?

Maybe you are migrating an old bash script that sets up a virtual machine or other OS environment to set up a Docker image instead. Maybe you’re trying to reduce the size of your images by combining all of your Docker commands into one shell script to run (though a multi-stage build might be more beneficial). Or maybe your command to run in Docker is actually or is started by a shell script. Depending on your use case, you will run your shell script in your Dockerfile slightly differently.

The three basic steps are:

  1. 1. COPYing the shell script into the Docker image through the Dockerfile, then either:
  2. 2. RUNning the script or
  3. 3. listing the script as the default command to run in the container with CMD

Step 1: COPYing the script over

After we have selected the Docker image on which to base our final image and installed packages, but before we use our script, we have to copy it over! Say that the script that we want to copy is in a child directory scripts from where we are building our container and that the script name is setup.sh. To copy it over, we would run

 …
 COPY scripts/setup.sh /opt/src/scripts/setup.sh
 …

Run in Warp

For more detail on copying files over to Docker, check out the official COPY documentation.

Note: Dockerfiles also support a command called ADD, which is similar to COPY. However, it behaves in a potentially unexpected way; for example, ADD automatically unpacks gzipped files. To avoid those unexpected surprises, I recommend using COPY for copying files and directories into a Docker image. (For more detail on ADD, please check out the official ADD documentation.)

Step 2: RUNing the script while building the Docker image

If we need to execute that script as part of building the Docker image, we need to RUN it!

 …
 RUN /opt/src/scripts/setup.sh
 …

Run in Warp

Any parameters we want to pass in go after the name of the script. For example: RUN /opt/src/scripts/setup.sh --environment dev.

If you want more examples or more options, there are many more details in the official RUN documentation

One note is that if you are consolidating a bunch of Dockerfile instructions into one shell script to reduce the number of intermediate images, thus trimming down total Docker container sizes and total time to build, structuring your Dockerfile into a multi-stage build might be more beneficial than using a script. See the official documentation for more details, but the gist is that we separate out several sets of Dockerfile instructions into different images for better Dockerfile instruction caching and a smaller final image that contains only what the container needs to run.

But I need to run a bash script or command in my Dockerfile!

The default shell for Linux-based containers is plain sh. If you need to run specifically with bash, you can either change the shell executing the commands with SHELL or call out to bash directly in the RUN statement:

 SHELL [“/bin/bash”, “-c”]
 # or 
 RUN /bin/bash -c '/opt/src/scripts/setup.sh’'

Run in Warp

The SHELL command is most useful if you are working in Windows, which has two different shells, or if you need many bash scripts executed in your Dockerfile. For more detail, check out the official SHELL documentation.

What is that bracket syntax you used for SHELL?

SHELL [“/bin/bash”, “-c”] is an example of the “exec-form” of running commands in Docker. This is in contrast to the “shell form” that we have been using in this article. In most cases, exec-form is recommended, but it behaves somewhat unexpectedly compared to running commands in a local terminal because it does not interpolate string variables, which can be common when running shell scripts.

For example, if you are using something like $PWD in your RUN command, use the syntax that we have been using. The official RUN documentation covers this in more detail.

Step 3: Setting a script as the default CMD to run for your image

The main purpose of a CMD instruction is to be a default program to execute when running your container. I prefer to be explicit and clear, especially with Docker which has so many options available, but if your container is really only used for one purpose, you can set it as the default in CMD:

 …
 CMD /opt/src/scripts/start-server.sh

Run in Warp

I don’t normally use this, but I am pointing it out for completeness’s sake. The official documentation for CMD lists more options and goes into the ENTRYPOINT instruction, which is related to the CMD instruction.

Dockerfiles have a lot of potential gotchas and places where small changes can have big speed and size implications. Docker has some great recommendations and best practices to aid you in your iteration process. I recommend starting reading at the .dockerignore section.

Written by

Thumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell WilsonThumbnail for Preston Tunnell Wilson
Preston Tunnell Wilson

Preston Tunnell Wilson

Senior Software Engineer, InStride Health

Filed Under

Related Articles

Override the Container Entrypoint With docker run

Learn how to override and customize the entrypoint of a Docker container using the docker run command.

Docker

The Dockerfile ARG Instruction

Learn how to define and set build-time variables for Docker images using the ARG instruction and the --build-arg flag.

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Start a Docker Container

Learn how to start a new Docker container from an image in both the foreground and the background using the docker-run command.

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Stop All Docker Containers

How to gracefully shutdown running containers and forcefully kill unresponsive containers with signals in Docker using the docker-stop and docker-kill commands.

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Use An .env File In Docker

Learn how to write and use .env files in Docker to populate the environment of containers on startup.

Docker

Run SSH In Docker

Learn how to launch and connect to a containerized SSH server in Docker using password-based authentication and SSH keys.

Docker
Thumbnail for Gabriel ManricksThumbnail for Gabriel ManricksThumbnail for Gabriel ManricksThumbnail for Gabriel Manricks
Gabriel Manricks

Launch MySQL Using Docker Compose

Learn how to launch a MySQL container in Docker Compose.

DockerSQL

Execute in a Docker Container

Learn how to execute one or multiple commands in a Docker container using the docker exec command.

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Expose Docker Container Ports

Learn how to publish and expose Docker container ports using the docker run command and Dockerfiles.

Docker

Restart Containers In Docker Compose

Learn how to restart and rebuild one or more containers in Docker Compose.

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Output Logs in Docker Compose

Learn how to output, monitor, customize and filter the logs of the containers related to one or more services in Docker Compose

Docker
Thumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan LudosanuThumbnail for Razvan Ludosanu
Razvan Ludosanu

Rename A Docker Image

Learn how to rename Docker images locally and remotely using the docker tag command.

Docker

Trusted by hundreds of thousands of professional developers

Download Warp to get started

Download for Mac
Request demo
Thumbnail for nullThumbnail for nullThumbnail for nullThumbnail for null