Wie schreibe ich Befehle mit mehreren Zeilen in Dockerfile, während die neuen Zeilen erhalten bleiben?

84

Ich möchte den folgenden RUN-Befehl in die Docker-Datei schreiben. Docker behält die neuen Zeilen jedoch nicht bei.

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

Ich weiß, dass \am Ende jeder Zeile die neue Zeile entweicht. Aber gibt es eine Möglichkeit, mehrere Zeilen zu schreiben, wobei die neue Zeile erhalten bleibt?

Venkata Jaswanth
quelle
Verwenden Sie eine Nicht-Nix-Plattform? Weil das für mich unter Linux gut funktioniert.
Benutzer
@user, ich habe Linux benutzt.
Venkata Jaswanth

Antworten:

114

Sie können das sogenannte "ANSI-C-Quoting" mit verwenden $'...'. Es war ursprünglich eine ksh93- Funktion , ist aber jetzt in bash, zsh, mksh, FreeBSD sh und in Busybox's Ash verfügbar (jedoch nur, wenn es mit ENABLE_ASH_BASH_COMPAT kompiliert wurde).

Da RUN standardmäßig /bin/shals Shell verwendet wird, müssen Sie zuerst mit der Anweisung SHELL zu etwas wie Bash wechseln.

Beginnen Sie Ihren Befehl mit $', beenden Sie ihn mit 'und verwenden Sie ihn \n\für Zeilenumbrüche wie folgt:

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
Daniel Zolnai
quelle
4
Es ist Bash-Syntax. Siehe diese Frage für weitere Informationen: stackoverflow.com/a/11966402/1395437
Daniel Zolnai
13
Bitte erklären Sie, was Sie tun, lassen Sie nicht einfach eine undurchsichtige Lösung fallen
Édouard Lopez
25
Ein Wort der Vorsicht: Die $' ... \n\ Technik hängt von der Shell ab, die Docker RUNverwendet bash. Auf einigen Systemen (wie Ubuntu) wird von der RUN-Shell /bin/shhäufig eine Verknüpfung verwendet, dashdie NICHT ist bashund die $'Syntax nicht versteht .
Anon
2
Wie @Anon sagte, funktioniert dies NICHT, wenn es irgendwo anders als Bash ausgeführt wird. (funktioniert auch nicht in Oh My Zsh)
Rafa
1
@Anon gut, es funktioniert unter Alpine Linux (derzeit bin ich auf 3.10.2), die Shell verwendet.
Suchoss
52

Ich habe benutzt printf. Schreiben Sie den gesamten Text mit "\ n" in eine Zeile.

Ausführen:

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

Beilagen:

example
text
here

in example.txt

CTodea
quelle
19

Sie können verwenden:

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

Auf diese Weise haben Sie eine schnelle Möglichkeit, den Inhalt der Datei zu überprüfen. Sie müssen sich nur bewusst sein, dass Sie jede Zeile mit beenden \und \nbei Bedarf einfügen müssen .

Paulo Fidalgo
quelle
1
Dies erfordert echo -ezu interpretieren\n
Patrick Bergner
5

Am Ende habe ich eine Kombination der oben aufgeführten Beispiele verwendet, da die neue Zeile \nnicht funktioniert hat echo.

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

Wie erwartet wird Folgendes erzeugt:

example
text
here
Sergey
quelle
Wie unterscheidet sich Ihre Antwort von der von CTodea?
Der Pate
@ TheGodfather Das ist ein mehrzeiliges Beispiel. Beantwortet auch besser die ursprüngliche Frage.
Sergey
2

Vielleicht hilft es Ihnen ( 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
jen-soft
quelle
-1

Sie können RUN mehrmals ausführen, um Ihre Datei zu vervollständigen:

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

Dies ist möglicherweise nicht die optimale Lösung, da für jeden RUN-Befehl eine neue Ebene erstellt wird. Trotzdem ist jede Ebene so groß wie die Änderung, die Sie vornehmen. In diesem Fall liegt sie in der Reihenfolge der Bytes (die erste RUN-Ebene sollte 7 Byte groß sein).

Der Vorteil dieser Lösung ist, dass sie mit allen Schalen funktioniert.

abel
quelle
1
Wahrscheinlich ist es besser, diese Befehle &&für bessere Caching-Zwecke, reduzierte Protokollierung und schnellere DockerfileErstellungszeiten zu verwenden
JohannesB