「スクリプトの中でコマンドに複数行の入力を渡したい」
こうした場面で使うのがbashのヒアドキュメント(here document)です。
echo を何十行も並べる必要はありません。
<< 演算子を使えば、複数行のテキストをそのまま扱えます。この記事では、ヒアドキュメントの基本構文から、設定ファイルの生成・シェルスクリプト内でのコマンド入力・インデント制御まで、現場で即使える実践的な使い方を解説します。RHEL 9.4 / Ubuntu 24.04 LTS で動作確認済みです。
この記事のポイント
・<<EOF で複数行テキストをそのままコマンドに渡せる
・<<'EOF'(シングルクォート)で変数展開を抑止できる
・<<-EOF でインデントのタブを自動除去できる
・設定ファイル生成・mysql入力・ssh越し実行の3パターンが定番
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
ヒアドキュメントとは何か
ヒアドキュメント(here document)は、シェルスクリプトで複数行のテキストをリテラルとして扱う構文です。通常のリダイレクト
> や < と同様に、コマンドへの入力として機能します。基本構文は次のとおりです。
コマンド <<EOF 1行目のテキスト 2行目のテキスト $変数名は展開される EOF
・終端文字列(ここでは
EOF)はどの文字列でも構わない。END・TEXT・SCRIPT なども使われる・終端文字列の行は行頭に書く(スペースやタブがあると終端と認識されない)
「ヒアドキュメント」という名前は「ここにドキュメントがある(here is the document)」という意味から来ています。
基本的な使い方
1. cat へ渡して画面表示する
最もシンプルな使い方が、cat への入力です。cat <<EOF Hello, Linux! Today is $(date +%Y-%m-%d) EOF
Hello, Linux! Today is 2026-05-27
$(date +%Y-%m-%d) はコマンド置換として実行されます。変数・コマンド置換が有効なのがデフォルトのヒアドキュメントの特徴です。2. ファイルへリダイレクトして設定ファイルを生成する
スクリプトで設定ファイルを動的に生成するのが、実務で最も多い使い方です。#!/bin/bash SERVER_IP="192.168.1.100" ADMIN_EMAIL="admin@example.com" cat > /etc/myapp/myapp.conf <<EOF # myapp 設定ファイル(スクリプト自動生成) server_ip=${SERVER_IP} admin_email=${ADMIN_EMAIL} log_level=info EOF
cat > ファイル名 <<EOF の形にすることで、変数を展開しながらファイルを上書きします。>> に変えれば追記になります。3. 変数展開を抑止する(シングルクォート形式)
終端文字列をシングルクォートで囲むと、変数展開・コマンド置換が一切行われません。PHPやbashのスクリプトファイル自体をテンプレートから生成するときに必須の書き方です。
cat > /tmp/check.sh <<'EOF' #!/bin/bash echo "現在のユーザー: $USER" echo "ホスト名: $(hostname)" EOF
#!/bin/bash echo "現在のユーザー: $USER" echo "ホスト名: $(hostname)"
$USER や $(hostname) がそのまま文字列として書き出されています。通常形式との使い分けを間違えると、スクリプトに意図しない展開結果が埋め込まれるので注意してください。
インデント制御(<<-EOF)
1. タブ除去オプションを使う
シェルスクリプトを関数の中で書くとき、ヒアドキュメント内のテキストがインデントできず見た目が崩れることがあります。<<-(ハイフン付き)を使うと、各行の先頭にあるタブ文字が自動的に除去されます。#!/bin/bash create_config() { cat > /etc/myapp.conf <<-EOF # タブでインデントしている server=localhost port=8080 EOF } create_config
エディタで自動的にスペースに変換する設定になっている場合は
<<- が機能しません。インデント文字が本当にタブかどうかを確認してから使いましょう。2. インデント除去を使わない場合の代替策
スペースインデントの環境では<<- が使えません。その場合は終端文字列を関数外に追い出すか、sed でインデントを除去するのが現場の定石です。# sedでスペースインデントを除去する例 cat <<EOF | sed 's/^ //' server=localhost port=8080 EOF
応用・実務Tips
1. mysqlコマンドへ複数行のSQLを渡す
データベース管理でよく使うパターンです。mysql -u root -p"${DB_PASS}" "${DB_NAME}" <<EOF CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(200) NOT NULL UNIQUE ); INSERT INTO users (name, email) VALUES ('admin', 'admin@example.com'); SHOW TABLES; EOF
mysql コマンドは標準入力をSQLとして実行します。スクリプト内でSQLを1行ずつ echo するよりはるかに可読性が高くなります。2. ssh越しにリモートで複数コマンドを実行する
sshのリモートコマンド実行にヒアドキュメントを組み合わせると、複数コマンドをまとめて送れます。ssh user@192.168.1.10 <<'EOF' echo "=== ディスク使用量 ===" df -h echo "=== メモリ使用量 ===" free -m echo "=== 直近のログ ===" journalctl -n 20 --no-pager EOF
<<'EOF' にしているので、変数はリモート側のシェルで展開されます。ローカルの変数を渡したい場合はダブルクォートなし(通常形式)にします。3. sudo teeで権限の高いファイルを書く
root権限が必要なファイルを書き換えるときは、sudo tee と組み合わせます。sudo cat > ... では cat が root でもリダイレクトはユーザー権限で処理されるため書き込めません。# NG: リダイレクト先がroot権限で保護されている場合は失敗する # sudo cat > /etc/sysctl.d/99-custom.conf << EOF # OK: sudo teeを使う cat <<EOF | sudo tee /etc/sysctl.d/99-custom.conf > /dev/null # カスタムカーネルパラメータ net.core.somaxconn = 65535 vm.swappiness = 10 EOF # 設定を即時反映する sudo sysctl --system
* Applying /usr/lib/sysctl.d/00-system.conf ... * Applying /etc/sysctl.d/99-custom.conf ... net.core.somaxconn = 65535 vm.swappiness = 10
4. Pythonなど他言語スクリプトをbashから生成・実行する
インフラ整備スクリプトで、一時的なPythonコードをbashから生成して実行するパターンです。#!/bin/bash TARGET_DIR="/var/log/myapp" python3 <<EOF import os import glob files = glob.glob('${TARGET_DIR}/*.log') print(f"ログファイル数: {len(files)}") for f in sorted(files): size = os.path.getsize(f) print(f" {f}: {size:,} bytes") EOF
${TARGET_DIR} はbash側で展開され、Pythonコードに埋め込まれます。本番環境でよく使う手法ですが、可読性が下がるため、コードが長くなるなら独立したPythonファイルに切り出す方が保守しやすいです。
トラブルシュート・エラー対処
1. 終端文字列が認識されない(heredoc never closes)
症状:スクリプトを実行しても終わらない、または「unexpected EOF」エラーが出る。原因:終端文字列(EOF)の行にスペースやタブが入っている。
# NG: EOFの前にスペースが入っている(<<- を使わない場合) cat <<EOF テキスト EOF ← これは終端と認識されない! # OK: EOFは必ず行頭から cat <<EOF テキスト EOF
<<- を使う場合はタブのみ除去されます。スペースが混在していると依然として終端と認識されません。2. 変数が展開されてしまう・されない
展開させたくないのに展開される:終端文字列をシングルクォートで囲む。展開させたいのに展開されない:シングルクォートを外す。
# 変数を展開する(デフォルト) cat <<EOF ユーザー: $USER EOF # 変数を展開しない(ファイル生成時に使う) cat <<'EOF' ユーザー: $USER EOF
3. sudo teeで書いても内容が空になる
症状:sudo tee でファイルを書いたがファイルが空になる。原因:
tee の前に /dev/null へのリダイレクトを付け忘れ、tee が標準出力に出力してしまい、それが別のリダイレクトに使われている。対処:
| sudo tee ファイル名 > /dev/null の形にして tee の標準出力を捨てる。4. シェルスクリプトでset -eと組み合わせると途中終了する
set -e 環境でヒアドキュメント内のコマンドが失敗すると、スクリプト全体が終了します。エラーが起きうる箇所は
|| true ではなく if 文で処理するか、その箇所だけ set +e で一時解除してください。set -e # 失敗しても継続したい場合は set +e / set -e で挟む set +e mysql -u root -p"${DB_PASS}" "${DB_NAME}" <<EOF DROP TABLE IF EXISTS tmp_work; EOF set -e
本記事のまとめ
| やりたいこと | 構文 |
|---|---|
| 複数行テキストをコマンドへ渡す(変数展開あり) | コマンド <<EOF ... EOF |
| 変数展開を抑止してファイルへ書き出す | cat > ファイル <<'EOF' ... EOF |
| 行頭のタブを除去してインデントを整える | コマンド <<-EOF ... EOF |
| root権限ファイルへ書き込む | cat <<EOF | sudo tee ファイル > /dev/null |
| ssh越しに複数コマンドを実行する | ssh user@host <<'EOF' ... EOF |
| mysqlへ複数行SQLを渡す | mysql -u root -p ... <<EOF ... EOF |
設定ファイル生成・データベース操作・リモート実行のどれにも使えるので、まず
cat > ファイル <<EOF の形から試してみてください。bashのシェルスクリプトをもっと深く学びたい方は、set -xコマンドでシェルスクリプトをデバッグする方法やgetoptsコマンドでbashスクリプトの引数を処理する方法もあわせてご覧ください。
また、コマンドの実行結果をファイルと画面に同時に残したい場面ではteeコマンドで標準出力とファイルに同時出力する方法が役立ちます。
シェルスクリプトのエラー処理を体系的に学ぶならtrapコマンドでbashスクリプトのシグナルを捕捉・処理する方法もあわせてどうぞ。
Linux Master Pro Seminar(2日間ハンズオン)では bashスクリプト・設定ファイル管理・サーバー自動化まで、
実際のサーバーを触りながら実務レベルのシェルスクリプト技術を習得できます。
>> セミナー詳細・お申込みはこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:podmanコマンドの使い方|DockerからPodmanへの移行方法とRHEL9対応の実践例
- 前のページへ:iperf3コマンドでLinuxのネットワーク帯域幅を測定する方法|サーバー間のスループット確認と実践例も
- この記事の属するカテゴリ:Linuxtips・シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます