docker
bash
dockerfile
scripting
devops

How to run bash function in Dockerfile

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A Dockerfile does not keep shell state between RUN instructions, so a Bash function defined in one layer is gone in the next one. If you want to use a Bash function during image build, define and call it in the same RUN step or put the function in a script file and execute that script.

Why the Function Disappears

Each RUN instruction starts a fresh shell process and commits the filesystem changes into a new image layer. Shell functions are in-memory shell state, not files, so they do not survive into the next RUN.

That means this does not work the way people expect:

dockerfile
RUN function hello() { echo hi; }
RUN hello

The second RUN cannot see the function because the first shell process has already exited.

Define and Use the Function in One RUN

If the function is small, keep it in the same instruction:

dockerfile
SHELL ["/bin/bash", "-c"]

RUN hello() { echo "hello from bash"; } && hello

This works because definition and execution happen in the same Bash process.

The SHELL directive matters here. Docker defaults to /bin/sh -c on many images, and plain sh may not support the Bash function syntax you are expecting.

Prefer Scripts for Anything Non-Trivial

For real build logic, a script file is usually better than a long inline shell expression.

setup.sh:

bash
1#!/usr/bin/env bash
2set -euo pipefail
3
4hello() {
5  echo "hello from script"
6}
7
8hello

Dockerfile:

dockerfile
1FROM ubuntu:22.04
2SHELL ["/bin/bash", "-c"]
3COPY setup.sh /tmp/setup.sh
4RUN chmod +x /tmp/setup.sh && /tmp/setup.sh

This is easier to read, easier to test locally, and much easier to maintain as the build grows.

Sourcing a Script Also Works

If you want to keep several helper functions in one file and call one of them during a build step, source the file in the same RUN:

dockerfile
SHELL ["/bin/bash", "-c"]
COPY helpers.sh /tmp/helpers.sh
RUN source /tmp/helpers.sh && install_dependencies

Again, it all happens in one shell process. That is the rule to remember.

Avoid Treating Dockerfiles Like Interactive Shell Sessions

A Docker build is not an interactive Bash session. It is a sequence of isolated build steps. Files persist between layers, but shell functions, aliases, and local variables do not unless you recreate them each time. That distinction becomes especially important when a Dockerfile grows from a quick prototype into a repeatable build pipeline, because hidden shell state assumptions then start causing non-obvious failures.

Once you understand that separation, the behavior stops being surprising.

Common Pitfalls

The biggest mistake is defining a Bash function in one RUN layer and trying to call it in another. That state does not persist.

Another issue is forgetting that the default shell may be /bin/sh rather than Bash. If the function syntax depends on Bash, set the SHELL directive explicitly or invoke bash -c yourself.

Developers also sometimes pack a large amount of shell logic into one unreadable RUN command. At that point, a script file is the cleaner solution.

Finally, do not confuse environment variables with shell functions. Variables can be made persistent with ENV, but functions are a different kind of shell state.

Summary

  • Bash functions do not persist across separate RUN instructions.
  • Define and call the function in the same RUN step, or use a script file.
  • Set the build shell to Bash if your syntax depends on it.
  • Source helper scripts and call functions in one shell process.
  • For non-trivial logic, prefer scripts over long inline Dockerfile commands.

Course illustration
Course illustration

All Rights Reserved.