ちょっとシェルでファイルの内容を処理するプログラムを作っていたら、思った通りに動かず難儀した
# cat list.txt
aaa
bbb
ccc
というファイルを読んで一列に並ばせたくて以下のシェルを作成する
#!/bin/sh
LIST=head
cat list.txt | while read line
do
LIST=”$LIST $line”
done
echo “LIST=” $LIST
さて、このシェルがどのように動くかというと
$ sh -x ./test.sh
+ LIST=head
+ cat list.txt
+ read line
+ LIST=’head aaa’
+ read line
+ LIST=’head aaa bbb’
+ read line
+ LIST=’head aaa bbb ccc’
+ read line
+ echo LIST= head
LIST= head
となる。
ループの中ではきちんと$LISTに追加されていくのに、最後はそんなことがなかったように消えてなくなる。
どうしたものかと調べたら、どうもシェル内にて制御構造にリダイレクトを行うと、サブシェルでの実行になるため、ループ内の変数はサブシェル内の変数となり、大元のシェルに影響しないとのことらしい…
これを回避するには、標準入力にファイルを接続してしまえとのこと、つまり
#!/bin/sh
LIST=head
exec < list.txt
while read line
do
LIST="$LIST $line"
done
echo "LIST=" $LIST
とすれば
$ sh -x ./test.sh
+ LIST=head
+ exec
+ read line
+ LIST='head aaa'
+ read line
+ LIST='head aaa bbb'
+ read line
+ LIST='head aaa bbb ccc'
+ read line
+ echo LIST= head aaa bbb ccc
LIST= head aaa bbb ccc
のように正常に動くということ。あまり、シェル内で標準入力とか気にしていなかったなぁと反省…