12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

シェルにおけるコマンド出力とループ処理の問題

Posted at

シェルスクリプトでコマンドの出力をループ処理する場合、コマンドとループをパイプ "|" で連結して処理をするのが一般的だけど、シェルの仕様によりパイプ "|" を使うとコマンドとループが別のプロセスになってしまうため、ループの内側でセットしたシェル変数をループの外側で参照できない等の問題がある。
(たまに『シェルによってはループが別プロセスになる』といった解説も見られるがそれは間違い)。

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}

12
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?