Шаблоны файлов и скриптов в Bash - метод heredoc
Введение
Heredoc (Here Documents) - это встроенный механизм командных оболочек (bash, sh, zsh), позволяющий передавать команде многострочный текст прямо из терминала, не создавая для этого временный файл. Проще говоря, это способ сказать оболочке: “Всё, что я напишу до слова-метки, воспринимай как единый стандартный ввод (stdin) для программы”. Метка должна быть написана на последней строчке с начала строки.
Базовый синтаксис:
команда << EOF
строка 1
строка 2
строка 3
EOF
- EOF (End Of File) - это просто популярное имя метки, вместо
EOFможно использовать любые другие слова (END, BLOCK, SCRIPT и т.п.).
Пример:
$ cat << EOF
Строка 1
Строка 2
Строка 3
EOF
=== Вывод ===
Строка 1
Строка 2
Строка 3
Подстановка переменных
Подстановка переменных по умолчанию включена:
$ name="Мир"
$ date=$(date)
$ cat << EOF
Привет, ${name}!
Текущая дата: ${date}
EOF
=== Вывод ===
Привет, Мир!
Текущая дата: Ср 12 авг 2026 09:26:00 MSK
Но если взять EOF в кавычки (одинарные или двойные), то переменные не будут подставляться:
$ cat << "EOF"
Привет, ${name}!
Текущая дата: $(date)
EOF
=== Вывод ===
Привет, ${name}!
Текущая дата: $(date)
- Кавычки вокруг метки нужны, чтобы подстановки не выполняла текущая оболочка до передачи текста.
- Если метка при открытии была в кавычках, закрывающая метка всё равно пишется без кавычек.
Не забудьте очистить переменные:
$ unset date
$ unset name
Создание файлов
С помощью этого метода можно создавать файлы, например:
$ cat > my_file.txt << EOF
Строка 1
Строка 2
Строка 3
EOF
$ cat my_file.txt
Строка 1
Строка 2
Строка 3
Важно! Если мы хотим этим методом записать файл используя sudo, то должны использовать другую конструкцию.
Так не работает:
sudo cat > /etc/privileged_file << EOF
...
EOF
- Оболочка обрабатывает перенаправления до того, как запускает команду.
- Вначале выполняется
> /etc/privileged_fileбез sudo и если нет прав, то мы получаем ошибку. - Если на предыдущем шаге мы получили ошибку, то
sudo catвообще не запустится.
Правильный вариант:
sudo tee /etc/privileged_file > /dev/null << EOF
...
EOF
- Команда
teeчитает свой стандартный ввод и пишет его в указанный файл, и одновременно в свой стандартный вывод (на экран). - Мы запускаем
teeчерезsudo- процесс работает с правами root, и может открыть и записать защищённый файл. - Так как команда
teeдублирует вывод на экран, то с помощью конструкции> /dev/nullмы убираем этот вывод.
Например вот так бы мы создавали файл конфигурации для Nginx:
$ sudo tee /etc/nginx/sites-available/my-site.conf >/dev/null << EOF
server {
listen 80;
server_name example.com;
root /var/www/html;
}
EOF
Использование в скриптах
Метода heredoc можно использовать и при написании своих скриптов на bash, например для оформления красивого вывода:
usage() {
cat << HELP
Использование: $0 [опции]
-h Показать эту справку
-f Указать файл
HELP
}
Автоматизация
С помощью heredoc можно выполнять многострочные SQL-запросы к базе данных (mysql или psql):
$ mysql -u root -p << EOF
CREATE DATABASE mydb;
USE mydb;
CREATE TABLE users (id INT, name VARCHAR(20));
EOF
- Пароль будет запрошен отдельно.
- Для автоматизации лучше настроить доступ без интерактивного ввода пароля: например, через
~/.my.cnfдля MySQL/MariaDB или~/.pgpassдля PostgreSQL.
Также мы можем выполнять bash скрипты без создания файлов. В качестве примера приведу мой реальный скрипт первоначальной настройки Debian, в котором я:
- обновляю систему
- устанавливаю некоторое ПО
- устанавливаю локали ru_RU.UTF-8 и en_US.UTF-8
- делаю локаль ru_RU.UTF-8 по умолчанию
- устанавливаю московский часовой пояс
bash << "EOF"
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update && apt-get dist-upgrade -y
apt-get install -y locales wget tzdata lbzip2 bash-completion
sed -i 's/^# *ru_RU.UTF-8/ru_RU.UTF-8/' /etc/locale.gen
grep -q '^ru_RU.UTF-8' /etc/locale.gen || echo 'ru_RU.UTF-8 UTF-8' >> /etc/locale.gen
sed -i 's/^# *en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen
grep -q '^en_US.UTF-8' /etc/locale.gen || echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen
locale-gen
update-locale LANG=ru_RU.UTF-8
ln -fs /usr/share/zoneinfo/Europe/Moscow /etc/localtime
echo Europe/Moscow > /etc/timezone
dpkg-reconfigure -f noninteractive tzdata
echo '. /etc/bash_completion' >> ~/.bashrc
echo 'export LANG="ru_RU.UTF-8"' >> ~/.bashrc
reboot
EOF
- Обратите внимание, здесь используется
"EOF"- экранирование с помощью кавычек. - Кавычки вокруг метки подавляют все подстановки (переменные, командные подстановки).
- Это нужно для того, чтобы в bash команды попадали такими какие они записаны, без кавычек переменные бы раскрылись до попадания в bash.
А также можем автоматизировать интерактивные программы, например sftp:
$ sftp user@server << EOF
put localfile.txt /remote/path/
bye
EOF
- Для SSH-соединений с паролем такой способ не подойдёт, используйте ключи.
Вопросы для самопроверки
- Напишите по памяти базовый синтаксис heredoc с командой
cat. - Что обозначает аббревиатура
EOFв heredoc? Можно ли использовать другое слово вместоEOF? - Подставляются ли переменные в heredoc? Если да, то можно ли это отключить?
- Почему для записи в
/etcчасто нужно использоватьsudo tee, а неsudo cat > file? - Напишите по памяти создание файла с помощью heredoc.
- Напишите по памяти создание защищенного файла с помощью heredoc.