heredoc(ヒアドキュメント)入門 - 複数行の文字列をスクリプトに埋め込む

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/filecat に 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"

次に読む