Что такое…

Что такое heredoc (<<EOF) — и почему из скрипта пропали все $

Иллюстрация: длинная лента бумаги уходит в латунную трубу, а в конце её останавливает деревянный брусок-метка

Ты просишь ИИ создать скрипт деплоя прямо из терминала. Он присылает команду:

cat > deploy.sh <<EOF
echo "Деплою ветку $1 в $HOME/app"
EOF

Ты запускаешь. Файл появился. Открываешь — а внутри:

echo "Деплою ветку  в /home/user/app"

$1 пропал. $HOME превратился в твою настоящую папку. Скрипт сломан ещё до первого запуска. Виноват не ИИ и не bash. Виновато одно отсутствующее слово в кавычках. Разберём, что такое heredoc — и где он кусается.

Что такое heredoc

Heredoc (от here document, «документ прямо здесь») — способ передать команде несколько строк текста прямо в терминале. Без отдельного файла.

Выглядит так:

cat <<EOF
Первая строка
Вторая строка
EOF

Знак << говорит: «дальше идёт текст». Слово после него — метка конца. Bash собирает все строки, пока не встретит эту метку одну на строке. Потом отдаёт собранное команде на вход, как будто текст лежал в файле.

Метка не обязана быть EOF. Можно END, TEXT, PROMPT. EOF просто привычка — от end of file, «конец файла».

Почему пропали $

Вот главная хитрость. Без кавычек heredoc ведёт себя как строка в двойных кавычках. Bash заглядывает внутрь и подставляет всё, что похоже на переменную или команду:

  • $HOME → твоя домашняя папка;
  • $1 → первый аргумент. В терминале его нет, значит, пусто;
  • $(date) → текущая дата. Команда выполнится прямо сейчас.

Иногда это то, что надо. Например, собрать письмо с именем пользователя. Но когда ты пишешь скрипт в файл, подстановка всё ломает. $ должны попасть в файл как есть, а сработать потом.

Лечится одной парой кавычек вокруг метки:

cat > deploy.sh <<'EOF'
echo "Деплою ветку $1 в $HOME/app"
EOF

Теперь bash не трогает ничего внутри. В файл ляжет ровно то, что ты видишь. Правило на всю жизнь: пишешь код в файл — бери 'EOF' в кавычках.

А если нужно и то и другое? Скажем, порт подставить сейчас, а $1 оставить на потом. Тогда метку оставь без кавычек, а нужные $ экранируй обратным слешем:

cat > run.sh <<EOF
echo "Запускаю \$1 на порту $PORT"
EOF

Здесь \$1 попадёт в файл как $1. А $PORT возьмётся из переменной окружения прямо сейчас. Смешивать так можно, но читать такое тяжело. Если экранированных $ больше двух — раздели текст на два heredoc.

Где ты его уже видел

Посмотри, как агенты вроде Claude Code делают коммит. Часто так:

git commit -m "$(cat <<'EOF'
fix: handle empty cart

Cart page crashed when the list was empty.
EOF
)"

Выглядит страшно, но теперь ты можешь прочитать это сам. Heredoc собирает многострочное сообщение. $(...) превращает его в одну строку для -m. А кавычки вокруг 'EOF' защищают текст: если в сообщении встретится $PATH или обратная кавычка, они не выполнятся.

Тот же приём годится, чтобы скормить модели длинный промпт из терминала. Например, claude -p с текстом через heredoc. Многострочный запрос без возни с экранированием.

Три грабли, на которые наступают все

1. Метка конца с пробелом. Закрывающее EOF должно стоять одно на строке. Без пробелов после и без отступа перед. Иначе bash его не узнает и будет ждать дальше. В скрипте это кончится предупреждением here-document delimited by end-of-file. В терминале — приглашением >, которое не уходит. Если такое случилось, про выход читай в разборе почему завис терминал.

2. Отступы через <<-. Хочешь красиво сдвинуть heredoc внутри if? Есть вариант <<-EOF: он срезает отступы в начале строк. Но только табы. Редактор тихо заменил табы пробелами — и heredoc перестал закрываться.

3. sudo и права. Команда sudo cat <<EOF > /etc/app.conf падает с Permission denied. Потому что > выполняет твоя оболочка, а не sudo. Права есть у cat, а файл открывает обычный ты. Рабочий вариант:

sudo tee /etc/app.conf > /dev/null <<'EOF'
port=8080
EOF

Здесь файл открывает tee, и он уже запущен через sudo.

Что такое <<< в bash?

Это here-string, младший брат heredoc. Он передаёт на вход одну строку: grep error <<< "$log". Удобно, когда текст уже лежит в переменной.

Чем heredoc лучше echo?

echo хорош для одной строки. На многострочном тексте начинаются \n, экранирование кавычек и разное поведение в разных оболочках. Heredoc читается как обычный текст — что видишь, то и получишь.

Heredoc работает в Windows?

В PowerShell похожая штука называется here-string и пишется через @' ... '@. В WSL и Git Bash работает обычный bash-heredoc.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →