while内部の変数が反映されない場合の対処 †パイプを使って、whileに渡し変数を操作すると、whileを抜けた後で変数を参照しても値が格納されない場合の対処方法です。 期待した動作をしないwhileスクリプト †#!/bin/bash # hostsの行をカウントします i=0 cat /etc/hosts | while read L do i=`expr $i + 1` echo inside: $i done echo outside: $i 実行結果 $ ./while1.sh inside: 1 inside: 2 inside: 3 inside: 4 inside: 5 inside: 6 inside: 7 inside: 8 <snip> outside 0 whileを抜けた後に、$iを出力すると、0になっています。 期待した動作をするスクリプト †パイプを使わず、リダイレクトを使う。 #!/bin/bash # hostsの行をカウントします i=0 while read L do i=`expr $i + 1` echo inside: $i done < /etc/hosts echo outside: $i 実行結果 $ ./while2.sh inside: 1 inside: 2 inside: 3 inside: 4 inside: 5 inside: 6 inside: 7 inside: 8 <snip> outside: 43 意図した動作になっています。 stdin(pipe)による場合の記述方法 †Process Substitutionを使うことにより解決します。 $ LANG=C man bash <snip> Process Substitution Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of <(list) or >(list). The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writ- ing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list. When available, process substitution is performed simultaneously with parameter and variable expan- sion, command substitution, and arithmetic expansion. <snip> $ man bash <snip> プロセス置換 プロセス置換 (process substitution) がサポートされるのは、 名前付きパイプ (FIFO) または ファイル・ディスクリプターの /dev/fd 形式で の指定 をサポートしているシステムです。これは <(list) または >(list) の形になります。 プロセス list は、その入力や出力が FIFO または /dev/fd 中の 何らかのファイルに接続された状態で実行されます。 このファイルの名前は、展開の結果として、 引き数の形で現在のコマンドに 渡されます。 >(list) の形式を使った場合、 ファイルへの書き込みは list への入力となります。 <(list) の形式を使った場合、 引き数として 渡されたファイルは list の出力を得るために読み込まれます。 利用可能であれば、プロセス置換 (process substitution) は、 パラメータ展開、変数展開、コマンド置換、算術式展開と同時に行われます。 <snip> 実際にstdinから記述したサンプルスクリプトを以下に記します。 #!/bin/bash CountLineStdin() { if [ ! -p /dev/stdin ]; then echo "stdin empty!" return 1 fi i=0 while read line do i=`expr $i + 1` echo "inside: $i" done < <(cat -) return 0 } CountLineStdin echo "outside: $i" 実行結果 $ cat /etc/hosts | ./while3.sh inside: 1 inside: 2 inside: 3 inside: 4 inside: 5 inside: 6 inside: 7 inside: 8 <snip> outside: 43 上記出力の通り、期待した動作になっています。 記述に関しての詳細は、man bashおよび、ネット調べてください。 以上、while内部の変数が反映されない場合の対処方法でした。 |