シェルスクリプトでヒアドキュメントを使う様々な方法 (bash / zsh)

シェルスクリプトでヒアドキュメントを使う様々な方法

なぜヒアドキュメントが必要なのか?

シェルスクリプトを作成して画面に何らかの文字列を表示する場合、echo コマンドで1行づつ文字列を画面に表示することが出来ますが、各行毎に echo コマンドを書いてあげなければなりません。また文字列を修正しなければならない場合にも echo コマンドをいちいち書く必要があるので非常に面倒です。

例えば以下のように echo コマンドを連続して書かなければなりませんが、1つのまとまった文章として書いたほうが可読性も高まりますし、修正が必要な際にメンテナンスが非常に楽になります。
#!/bin/bash

echo "123"
echo "123"
echo "123"
echo "ABC"
echo "DEF"
echo "GHI"

これを解決するためにシェルにはヒアドキュメントという機能が存在しています。ここではシェルスクリプトでヒアドキュメントを扱う様々な方法を解説します。




シェルスクリプトでヒアドキュメントを使うには?

シェルスクリプトでヒアドキュメントを使うには、以下のように "<<文字列終端文字" と "文字列終端文字" の間に文字列や変数あるいはコマンドを書きます。ここでは文字列終端文字は全て EOD (End Of Document の略) で統一して説明します。また全てのコードは bash と zsh で動作検証しています。

通常のヒアドキュメントの書き方

まず通常の文字列をヒアドキュメントで表示してみます。
#!/bin/bash

cat <<EOD
123
456
789
ABC
DEF
GHI
EOD


./heredoc.sh
123
456
789
ABC
DEF
GHI

変数展開とコマンド実行

次に変数とコマンドをヒアドキュメントの中に記述します。変数の中身が展開され、またバッククォート (`) で囲まれた Linux コマンドも実行されていることが分かります。
#!/bin/bash

VAR="Hello World"

cat <<EOD
123
456
789
${VAR}
`date`
ABC
DEF
GHI
EOD


$ ./heredoc.sh
123
456
789
Hello World
`date`
ABC
DEF
GHI

変数展開とコマンド実行をしないようにする

変数が展開されると困る場合には文字列終端文字をダブルクォーテーション (") で囲んであげると変数展開やコマンドが実行されることなく、そのまま文字列として扱われるようになります。
#!/bin/bash

VAR="Hello World"

cat <<"EOD"
123
456
789
${VAR}
`date`
ABC
DEF
GHI
EOD


$ ./heredoc.sh
123
456
789
${VAR}
`date`
ABC
DEF
GHI
同じようにシングルクォーテーション (') で文字列終端文字を囲んでも同じように変数展開やコマンドが実行されることなく、そのまま文字列として扱われるようになります。
#!/bin/bash

VAR="Hello World"

cat <<'EOD'
123
456
789
${VAR}
`date`
ABC
DEF
GHI
EOD


$ ./heredoc.sh
123
456
789
${VAR}
`date`
ABC
DEF
GHI

ヒアドキュメント内でインデントを使う

もし表示する文字列をインデントしたい場合には "<<-EOD" として文字列終端文字の直前にハイフン (-) を付けてあげると、スクリプトに書いたままのインデントが反映されるようになります。
$ cat ./heredoc.sh 
#!/bin/zsh

VAR="Hello World"

cat <<-EOD
  123
  456
  789
  ${VAR}
  `date`
  ABC
  DEF
  GHI
EOD


$ ./heredoc.sh 
  123
  456
  789
  Hello World
  2017年 11月 20日 月曜日 03:03:16 JST
  ABC
  DEF
  GHI

ヒアドキュメントで書いた内容を変数に代入する

今度はヒアドキュメントで書いた文章を変数に入れておきたい場合、次のようにして cat コマンドを組み合わせて変数に代入することが出来ます。
$ cat ./heredoc.sh 
#!/bin/zsh

VAR="Hello World"

MESSAGE=$(cat <<-EOD
  123
  456
  789
  ${VAR}
  `date`
  ABC
  DEF
  GHI
EOD)

echo ${MESSAGE}


$ ./heredoc.sh 
  123
  456
  789
  Hello World
  2017年 11月 20日 月曜日 03:14:11 JST
  ABC
  DEF
  GHI