「while」ループで変数を設定するために「読み取り変数」を使用する場合はグローバル変数ですが、「読み取り中に変数」を使用して変数を設定するときはローカル変数であるのはなぜですか?

「while」ループで変数を設定するために「読み取り変数」を使用する場合はグローバル変数ですが、「読み取り中に変数」を使用して変数を設定するときはローカル変数であるのはなぜですか?
unset myVariable i;
while [ -z "$i" ]; do
    read myVariable;
    echo "myVariable : '$myVariable'";
    i=foo;
done;
echo "myVariable : '$myVariable'"

unsetコマンドの再生を許可します)

任意のキーを押して+Enterキーを押すと、次のようになります。

myVariable : '[what you typed]'
myVariable : '[what you typed]'

値がループmyVariableの外側に存在します。while今試してください:

tmpFile=$(mktemp);
echo -e 'foo\nbar\nbaz' >> "$tmpFile"
while read myVariable; do
    otherVariable=whatever; 
    echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
done < "$tmpFile";
echo "myVariable : '$myVariable', otherVariable : '$otherVariable'";
rm "$tmpFile"

あなたは得るでしょう:

myVariable : 'foo', otherVariable : 'whatever'
myVariable : 'bar', otherVariable : 'whatever'
myVariable : 'baz', otherVariable : 'whatever'
myVariable : '', otherVariable : 'whatever'

myVariableループを出ると値が失われます。

なぜ別の行動をするのですか?わからない範囲指定のコツがありますか?

注:GNU bashバージョン4.4.12(1)リリース(x86_64-pc-linux-gnu)の実行

答え1

while read myVariable; do

myVariableループを出ると値が失われます。

いいえ、myVariable前回取得した値がありますread。スクリプトは、最後の改行文字の次の位置に達するまでファイルから読み取られます。その後、最終read呼び出しはファイルから何も取得せず、myVariableそれに応じて空の文字列に設定され、区切り文字(改行)が表示されないため、エラー値で終了します。その後、サイクルは終了する。

read最後の改行の後に不完全な行がある場合は、最後にNULL以外の値を取得できます。

$ printf 'abc\ndef\nxxx' | 
    { while read a; do echo "got: $a"; done; echo "end: $a"; } 
got: abc
got: def
end: xxx

あるいは、while read a || [ "$a" ]; do ...ループ本体の最後の行の断片を処理するために使用されます。

答え2

whileループにパイプを接続しているため、whileループを実行するためのサブシェルが作成されます。このサブプロセスには独自の環境コピーがあり、UNIXプロセスと同様に、どの変数も親プロセスに戻すことはできません。

この場合、done < "$tmpFile"リダイレクトはbashにサブシェル(パイプ用)を作成するように強制します。

から引用bash 変数の範囲スタックオーバーフローに。

答え3

2番目の例では、whileリダイレクトされた入力を含むループを使用します。

これはusingを読み取り、多くの< "$tmpFile"シェルがこの場合のサブシェルを生成します。を使用してこのスクリプトを実行してみることができますksh93ksh93この場合、サブシェルは作成されません。

場合によっては、理由は完全に異なります。

  • 最初の例では、入力から1行を読み取ります。

  • 2番目の例では、EOF到達するまで読みます。

コマンドreadは入力を読み取り、入力を文字に分割し、単語IFSを変数引数に代入しますread

コマンド引数として変数よりも単語が多い場合、read最後の変数は残りの単語を連結します。

変数よりも単語数が少ない場合、他の変数にはNULL値が割り当てられます。

をクリックしたので、EOF単語を読み取らずに代わりに1つ以上の変数を引数として渡しましたread。これにより、すべての変数にNULL値が割り当てられます。

したがって、予期しないことが発生します。EOFこれによりwhileループが終了し、echoループ内にコマンドは表示されませんが、この場合、ループの後のwhile最後のコマンドのみが表示されます。echowhileEOF

この final はechohit から消去された変数の内容を出力しますEOF

関連情報