シェルスクリプトでコマンドの出力をループ処理する場合、コマンドとループをパイプ "|" で連結して処理をするのが一般的だけど、シェルの仕様によりパイプ "|" を使うとコマンドとループが別のプロセスになってしまうため、ループの内側でセットしたシェル変数をループの外側で参照できない等の問題がある。
(たまに『シェルによってはループが別プロセスになる』といった解説も見られるがそれは間違い)。
sample
# !/bin/sh
# コマンドの出力をパイプでループに連結
command="/path/to/command"
count=0
${command} |
while read line
do
:
# 変数 count をインクリメント
count=`expr ${count} + 1`
done
# count の値は 0
echo ${count}
パイプを使うと別プロセスになるならパイプを使わないでコマンドの出力をループに流し込めば良いじゃ無いか、
という事で、ヒアドキュメントとシェルビルトインの exec (1) を利用してコマンドの出力を while ループの標準入力にしてしまうのが一番汎用的で柔軟性のある対応だと思うのでその方式。
勿論一時ファイルを作成しても良いのだが、ヒアドキュメントを利用する事で一時ファイルが不要になる分だけ処理的に美しいかなと思う(完全に好みの問題)。
sample
# !/bin/sh
# コマンドの出力をバッククォートしてヒアドキュメントとして使用する
command="/path/to/command"
count=0
# exec 3<&0: 標準入力 (FD0) を FD3 に複製
# exec 0<<EOF: ヒアドキュメントを標準入力として使用
exec 3<&0 0<<EOF
`${command}`
EOF
while read line
do
:
# 変数 count をインクリメント
count=`expr ${count} + 1`
done
# exec 0<&3: FD3 に複製した標準入力 (FD0) を復帰
# exec 3<&-: FD3 をクローズ</i>
exec 0<&3 3<-
# count の値はインクリメントされている
echo ${count}