¿Cómo escribir comandos con varias líneas en Dockerfile conservando las nuevas líneas?

84

Quiero escribir el siguiente comando RUN en el Dockerfile. Pero Docker no conserva las nuevas líneas.

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

Sé que \al final de cada línea se escapa la nueva línea. Pero, ¿hay alguna forma de que pueda escribir varias líneas conservando la nueva línea?

Venkata Jaswanth
fuente
¿Está utilizando una plataforma que no sea * nix? Porque esto funciona bien para mí en Linux.
usuario
@usuario, estaba usando Linux.
Venkata Jaswanth

Respuestas:

114

Puede utilizar lo que se denomina "cotización ANSI-C" con $'...'. Originalmente era una característica de ksh93 pero ahora está disponible en bash, zsh, mksh, FreeBSD sh y en el ash de busybox (pero solo cuando está compilado con ENABLE_ASH_BASH_COMPAT).

Como RUN usa /bin/shcomo shell por defecto , se requiere que cambie primero a algo como bash usando la instrucción SHELL.

Comience su comando con $', termínelo con 'y utilícelo \n\para nuevas líneas, así:

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
fuente
4
Es sintaxis bash. Consulte esta pregunta para obtener más información: stackoverflow.com/a/11966402/1395437
Daniel Zolnai
13
Por favor, explique lo que está haciendo, no deje caer una solución opaca
Édouard Lopez
25
Una advertencia: la $' ... \n\ técnica depende del shell que RUNutilice Docker bash. En algunos sistemas (como Ubuntu), el shell RUN que utiliza /bin/shes a menudo un enlace al dashque NO lo es bashy no comprende la $'sintaxis.
Anon
2
como dijo @Anon, esto NO FUNCIONARÁ si se ejecuta en otro lugar que no sea bash. (no funciona en Oh My Zshninguno de los dos)
Rafa
1
@Anon bien, funciona en Alpine Linux (actualmente estoy en 3.10.2) que usa shell.
suchoss
52

Yo usé printf. Escribir todo el texto en una línea usando "\ n".

Ejecutando:

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

inserciones:

example
text
here

en ejemplo.txt

CTodea
fuente
19

Puedes usar:

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

De esta manera, tendrá una forma rápida de verificar el contenido del archivo. Solo debe tener en cuenta que debe terminar cada línea con \e insertar el \ncuando sea necesario.

Paulo Fidalgo
fuente
1
Esto requiere echo -einterpretar\n
Patrick Bergner
5

Terminé usando una combinación de los ejemplos enumerados anteriormente ya que la nueva línea \nno funcionó con echo.

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

Produce lo siguiente, como se esperaba:

example
text
here
Sergey
fuente
¿En qué se diferencia su respuesta de la de CTodea?
El padrino
@TheGodfather Ese es un ejemplo de varias líneas. Mejor responde también a la pregunta original.
Sergey
2

Puede que te ayude ( 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-suave
fuente
-1

Puede ejecutar RUN varias veces para completar su archivo:

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

Esta puede no ser la solución óptima porque crea una nueva capa para cada comando RUN. Aún así, cada capa será tan grande como el cambio que realice, que en este caso es del orden de Bytes (la primera capa RUN debe ser de 7 bytes).

El beneficio de esta solución es que funcionará con todos los shells.

Abel
fuente
1
Probablemente sea mejor combinar estos comandos con &&mejores propósitos de almacenamiento en caché, registro reducido y Dockerfiletiempos de compilación más rápidos
JohannesB