Как писать команды с несколькими строками в Dockerfile, сохраняя при этом новые строки?

86

Я хочу написать следующую команду RUN в Dockerfile. Но докер не сохраняет новые строки.

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

Я знаю, что \в конце каждой строки выходит новая строка. Но есть ли способ написать несколько строк, сохраняя новую строку?

Венката Джасвант
источник
Вы используете платформу, отличную от * nix? Потому что у меня это нормально работает в Linux.
пользователь
@user, я использовал Linux.
Venkata Jaswanth

Ответы:

115

Вы можете использовать так называемое "цитирование ANSI-C" с $'...'. Изначально это была функция ksh93, но теперь она доступна в bash, zsh, mksh, FreeBSD sh и в золе busybox (но только когда она скомпилирована с ENABLE_ASH_BASH_COMPAT).

Поскольку RUN /bin/shпо умолчанию используется как оболочка вам необходимо сначала переключиться на что-то вроде bash, используя инструкцию SHELL.

Начните свою команду с $', завершите ее 'и используйте \n\для новых строк, например:

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
Даниэль Зольнай
источник
4
Это синтаксис bash. См. Этот вопрос для получения дополнительной информации: stackoverflow.com/a/11966402/1395437
Daniel Zolnai
13
Пожалуйста, объясните, что вы делаете, а не просто роняйте непрозрачный раствор
Эдуард Лопес,
25
Предупреждение: $' ... \n\ метод зависит от оболочки, которую RUNиспользует docker bash. В некоторых системах (таких как Ubuntu) RUN использует оболочку, /bin/shкоторая часто является ссылкой на dashкоторую НЕ является bashи не понимает $'синтаксиса.
Anon
2
как сказал @Anon, это НЕ РАБОТАЕТ, если запускать где-нибудь еще, кроме bash. (ни в Oh My Zshодном из них не работает )
Рафа
1
@Anon хорошо, что он работает в Alpine linux (в настоящее время я нахожусь на 3.10.2), который использует оболочку.
suchoss
53

Я использовал printf. Запись всего текста в одну строку с использованием «\ n».

Выполнение:

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

вставки:

example
text
here

в example.txt

CTodea
источник
19

Вы можете использовать:

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

Таким образом, у вас будет быстрый способ проверить содержимое файла. Вам просто нужно знать, что вам нужно заканчивать каждую строку \и вставлять, \nкогда это необходимо.

Пауло Фидальго
источник
1
Это требует echo -eинтерпретации\n
Патрик Бергнер
7

В итоге я использовал комбинацию примеров, перечисленных выше, поскольку новая строка \nне работала echo.

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

Как и ожидалось, он производит следующее:

example
text
here
Сергей
источник
1
Чем ваш ответ отличается от ответа CTodea?
The Godfather
@TheGodfather Это многострочный пример. Лучше также отвечает на исходный вопрос.
Сергей
2

Может быть, это вам поможет ( 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
Джен-Софт
источник
-1

Вы можете выполнить RUN несколько раз, чтобы завершить свой файл:

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

Это может быть не оптимальным решением, поскольку оно создает новый уровень для каждой команды RUN. Тем не менее, каждый уровень будет такого же размера, как и внесенное вами изменение, которое в данном случае имеет порядок байтов (первый уровень RUN должен быть 7-байтовым).

Преимущество этого решения в том, что оно будет работать со всеми оболочками.

Авель
источник
2
Вероятно, лучше объединить эти команды с &&целью лучшего кэширования, уменьшения количества журналов и ускорения времени Dockerfileсборки
JohannesB