heredoc(ヒアドキュメント)入門 - 複数行の文字列をスクリプトに埋め込む
ヒアドキュメントとは何か?
複数行の文字列をスクリプトに直接埋め込む構文。<<EOF で開始し、単独行の EOF で終端する。echo の多段呼び出しや連結より可読性が高く、設定ファイル生成・SQL 実行・SSH コマンド投入で頻繁に使われる。
基本構文
<<終端文字列 に続けて本文を書き、終端文字列を単独行に置く。
cat <<EOF 1行目のテキスト 2行目のテキスト 3行目のテキスト EOF
1行目のテキスト 2行目のテキスト 3行目のテキスト
終端文字列は EOF / END / HEREDOC など任意の文字列を使えるが、EOF(End Of File の略)が慣例。
終端文字列はカラム 0 から始めなければならない。前後に空白やタブがあると終端と認識されず、スクリプトがハングする。
変数展開はデフォルトで有効
<<EOF(クォートなし)では、ヒアドキュメント内の変数やコマンド置換がシェルによって展開される。
NAME="Alice" TODAY=$(date +%Y-%m-%d) cat <<EOF こんにちは、$NAME さん 今日は $TODAY です EOF
こんにちは、Alice さん 今日は 2026-06-01 です
展開を無効にしたい場合は、終端文字列をシングルクォートで囲む。
NAME="Alice" cat <<'EOF' Hello, $NAME $(date) は展開されない EOF
Hello, $NAME $(date) は展開されない
使い分けの目安
- Bash スクリプトで変数を埋め込む →
<<EOF(デフォルト) - テンプレートやコードスニペットをそのまま出力する →
<<'EOF'
インデントを除去する <<-
通常のヒアドキュメントは先頭の空白をそのまま出力する。<<- を使うと、先頭のタブ文字のみ除去できる。スクリプト本体のインデントと合わせて書きたい場合に使う。
if true; then cat <<-EOF インデントされたブロック タブが除去されて出力される EOF fi
インデントされたブロック タブが除去されて出力される
除去されるのはタブ(\t)のみ。スペースは除去されない。エディタをスペースインデントで使っている場合は、ヒアドキュメントの行をタブに変換する必要がある。
ファイルへの書き込み
リダイレクトと組み合わせることで、設定ファイルをスクリプトから直接生成できる。
cat <<EOF > /tmp/config.conf host=localhost port=5432 dbname=mydb EOF
追記の場合は >>:
cat <<EOF >> /tmp/config.conf user=admin password=secret EOF
root 権限が必要なファイルへの書き込みは tee を使う(sudo cat <<EOF > /root/file は cat に sudo が適用されてもリダイレクト先への書き込みは一般ユーザー権限になるため)。
cat <<EOF | sudo tee /etc/myapp/config.conf host=localhost port=5432 EOF
実践例 — SSH 経由でまとめてコマンドを実行
ssh user@server <<EOF echo "デプロイ開始" cd /var/www/myapp git pull origin main systemctl restart myapp EOF
変数をローカルで展開してからリモートに送りたい場合は <<EOF、リモート側のシェルで展開させたい場合は <<'EOF' を使い分ける。
実践例 — MySQL にクエリを流し込む
mysql -u root -p mydb <<EOF SELECT id, name FROM users WHERE active = 1; UPDATE users SET last_login = NOW() WHERE id = 42; EOF
複数のクエリをまとめて実行できるため、初期化スクリプトやバッチ処理で頻繁に使われる。
よくある落とし穴
終端文字列の前後に空白・タブを入れない
# NG: 終端 EOF の前に空白があると終端と認識されずスクリプトがハングする cat <<EOF 内容 EOF EOF
正しくは終端文字列をカラム 0 から始める(<<- の場合はタブのみ許可)。
バックスラッシュによる変数エスケープ
<<EOF(展開有効)でドル記号をそのまま出力したい場合は \$ でエスケープする。
cat <<EOF ホームディレクトリ: \$HOME 実際の値: $HOME EOF
ホームディレクトリ: $HOME 実際の値: /home/alice
変数に代入する
ヒアドキュメントをコマンドに渡す代わりに変数に格納したい場合は、$() でコマンド置換を使う。
TEXT=$(cat <<EOF 複数行の テキストを 変数に格納 EOF ) echo "$TEXT"