シェルスクリプトではwhile文の中で変数の値を書き換えてもwhile文を抜けた後に値の変更が反映されていないことがある。
説明を省略して対処法だけ書くと、パイプを使わずにヒアドキュメントを使えばよい。
2020/4/12追記
Process Substitutionという機能を使った方がいいらしいです。
参考記事:https://qiita.com/kawaz/items/6fd4cd86ca98af644a05
サンプル
一つ目のwhile文ではパイプで文字列を入力しているため、while文の後で$i
を参照しても1
になってしまうが、二つ目のwhile文はヒアドキュメントを使っているので、後で$i
を参照すると変更が反映されて6
が表示される。
#!/bin/bash
STR="\
a
b
c
d
e"
echo "Using pipe"
i=1
echo "$STR" | while read line ; do
echo $i, $line
i=$(( $i + 1 ))
done
echo $i
echo
echo "Using heredocument"
i=1
while read line ; do
echo $i, $line
i=$(( $i + 1 ))
done << END
$STR
END
echo $i
実行結果
Using pipe
1, a
2, b
3, c
4, d
5, e
1
Using heredocument
1, a
2, b
3, c
4, d
5, e
6
##解説
パイプを使うと次のコマンドは子プロセスとしてforkされる。そのため、サンプルコードの一つ目のwhile文は別のプロセスとなり、その中で変更された$i
は親プロセスには反映されず、while文の外で$i
の値を使用することができない。
だが、二つ目のヒアドキュメントを使ったwhile文では、同じプロセスでwhile文が実行されるためwhile文の外でも$i
の値を使用することができる。
また、プロセスをforkするときに変数はコピーされるため、パイプを使ったwhile文でも親プロセスの変数をwhile文の中で使用できる。そのため、サンプルコードではi=0
からではなく、while文の前で初期化されたi=1
から始まっている。