シェルスクリプトのパイプとループとサブシェルの罠
何が困るかというと、while内でカウントアップしたいときに困ります。
#!/bin/bash
COUNT=0
echo -e "a\nb\nc" | while read line
do
echo $line
COUNT=$(expr $COUNT + 1)
done
echo $COUNT # 出力:0
ループを抜けた瞬間にカウンターはゼロになってしまいます。これは困る。メカニズム
なぜこうなってしまうのでしょうか?わかりやすい解説を見つけたので引用します。
それは while のせいではなくパイプ (|) のせいです。
「|」で多段に接続された各々のコマンドは別プロセスとして動きますので、そのいずれのプロセスも親である shell に変数を渡すことは出来ません。
パイプの場合、前段の実行が完了しなくても後段の実行が始まります。
これは個々のプロセスが親である shell とは独立して動いていることを意味しますので、その while は sub shell と呼ばれる子プロセスによって実行されている訳です。
shell 変数は一つのプロセス内でしか共有出来ませんから、その内容を他のプロセスから見ることは不可能です。ファイルに吐き出すか、もしくはパイプ以外の手段を講じるかですね。
パイプを使わなければおk
ではどう対処すればいいかというと、パイプを使わずにうまくやればいけます。パイプを使わない例
COUNT=0
for line in a b c
do
echo $line
COUNT=$(expr $COUNT + 1)
done
echo $COUNT # 出力:3
一時ファイルを使う例
処理対象を一時ファイルに書きだしてからwhile read line
do
...
done < file.txt
などとやるのも有効です。参考
カテゴリ:
Bash