How to write commands with multiple lines in Dockerfile while preserving the new lines?

DockerDockerfile

Docker Problem Overview


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         = https://example.com/packages/ \
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?

Docker Solutions


Solution 1 - Docker

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         = https://example.com/packages/ \n\
enabled         = 1 \n\
gpgcheck        = 0' > /etc/yum.repos.d/Repo.repoxyz

Solution 2 - Docker

I used printf. Writing all the text in one line using \n.

Executing:

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

inserts:

example
text
here

in example.txt

Solution 3 - Docker

You can use:

RUN echo -e "\
[repo] \n\
name            = YUM Repository \n\
baseurl         = https://example.com/packages/ \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.

Solution 4 - Docker

I ended up using a combination of the examples listed above 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

Solution 5 - Docker

May be it's help you ( https://github.com/jen-soft/pydocker )

[ 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     http://security.debian.org/ jessie/updates main
deb-src http://security.debian.org/ 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- https://get.docker.com/ | sh

python Dockerfile.py
docker images

Solution 6 - Docker

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.3-labs
    
  3. Rewrite your heredoc like so:
    COPY <<EOF /etc/yum.repos.d/Repo.repoxyz
    [repo]
    name            = YUM Repository
    baseurl         = https://example.com/packages/
    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.

Solution 7 - Docker

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         = https://example.com/packages/" >> /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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVenkata JaswanthView Question on Stackoverflow
Solution 1 - DockerDaniel ZolnaiView Answer on Stackoverflow
Solution 2 - DockerCTodeaView Answer on Stackoverflow
Solution 3 - DockerPaulo FidalgoView Answer on Stackoverflow
Solution 4 - DockerSergeyView Answer on Stackoverflow
Solution 5 - Dockerjen-softView Answer on Stackoverflow
Solution 6 - DockerryanView Answer on Stackoverflow
Solution 7 - DockerabelView Answer on Stackoverflow