How to Write Commands with Multiple Lines in Dockerfile While Preserving the New Lines?

I want to write the following RUN command in the Dockerfile. But, docker is not preserving the new lines.

RUN echo "[repo] \
name            = YUM Repository \
baseurl         =  \
enabled         = 1 \
gpgcheck        = 0" > /etc/yum.repos.d/Repo.repoxyz

I know that \ at the end of each line escapes the new line. But, is there any way that I can write multiple lines preserving the new line?

2

7 Answers

You can use what is called "ANSI-C quoting" with $'...'. It was originally a ksh93 feature but it is now available in bash, zsh, mksh, FreeBSD sh and in busybox's ash (but only when it is compiled with ENABLE_ASH_BASH_COMPAT).

As RUN uses /bin/sh as shell by default you are required to switch to something like bash first by using the SHELL instruction.

Start your command with $', end it with ' and use \n\ for newlines, like this:

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

RUN echo $'[repo] \n\
name            = YUM Repository \n\
baseurl         =  \n\
enabled         = 1 \n\
gpgcheck        = 0' > /etc/yum.repos.d/Repo.repoxyz
11

Use printf to allow a single RUN command to output multiple lines of text, using \n to insert newlines.

Executing:

RUN printf 'example\ntext\nhere' >> example.txt

appends:

example
text
here

to the file example.txt

1

You can use:

RUN echo -e "\
[repo] \n\
name            = YUM Repository \n\
baseurl         =  \n\
enabled         = 1 \n\
gpgcheck        = 0\
" > /etc/yum.repos.d/Repo.repoxyz

This way you will have a quick way to check what the file contents are. You just need to be aware that you need to end every line with \ and insert the \n when needed.

3

I ended up using a combination of the examples listed here since the new line \n did not work with echo.

RUN printf 'example \n\
text \n\
here' >> example.txt

It produces the following, as expected:

example
text
here
2

As of Docker 18.09 and Dockerfile syntax 1.4, Dockerfiles support heredocs (ie what you're looking for here) natively!

  1. Enable BuildKit, eg by setting DOCKER_BUILDKIT=1.
  2. Add this line to the top of your Dockerfile:
    # syntax=docker/dockerfile:1.4
    
    or as recommended in the documentation
    # syntax=docker/dockerfile:1
    
  3. Rewrite your heredoc like so:
    COPY <<EOF /etc/yum.repos.d/Repo.repoxyz
    [repo]
    name            = YUM Repository
    baseurl         = 
    enabled         = 1
    gpgcheck        = 0
    EOF
    

You can also use this to run multiple bash commands in a single RUN block, etc. More details: Docker blog post, Dockerfile syntax docs.

3

May be it's help you ( )

[ Dockerfile.py ]

from pydocker import DockerFile  # sudo pip install -U pydocker

d = DockerFile(base_img='debian:8.2', name='jen-soft/custom-debian:8.2')

d.RUN_bash_script('/opt/set_repo.sh', r'''
cat >/etc/apt/sources.list <<EOL
deb      jessie/updates main
deb-src  jessie/updates main
EOL
apt-get clean && apt-get update
''')

d.EXPOSE = 80
d.WORKDIR = '/opt'
d.CMD = ["python", "--version"]

# d.generate_files()
d.build_img()

# sudo wget -qO-  | sh

python Dockerfile.py
docker images

You can execute RUN several times to complete your file:

RUN echo "[repo]" >> /etc/yum.repos.d/Repo.repoxyz
RUN echo "name            = YUM Repository" >> /etc/yum.repos.d/Repo.repoxyz
RUN echo "baseurl         = " >> /etc/yum.repos.d/Repo.repoxyz
RUN echo "enabled         = 1" >> /etc/yum.repos.d/Repo.repoxyz
RUN echo "gpgcheck        = 0" >> /etc/yum.repos.d/Repo.repoxyz

This may not be the optimal solution because it creates a new layer for every RUN command. Still, every layer will be as big as the change you make, which in this case it's in the order of Bytes (first RUN layer should be 7-byte).

The benefit of this solution is that it will work with all shells.

2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Sophia Al-Mansoor

Sophia Al-Mansoor

Global Business & E-Commerce Reporter

Sophia analyzes international trade, startup ecosystems, retail transformation, and supply chain logistics for modern digital publications.

Share this article
Twitter Facebook Pinterest