私の変数が1つの「読み込み中」ループではローカルですが、一見似ている他のループではローカルではないのはなぜですか?

私の変数が1つの「読み込み中」ループではローカルですが、一見似ている他のループではローカルではないのはなぜですか?

$x以下のコードスニペットと異なる値を取得するのはなぜですか?

#!/bin/bash

x=1
echo fred > junk ; while read var ; do x=55 ; done < junk
echo x=$x 
#    x=55 .. I'd expect this result

x=1
cat junk | while read var ; do x=55 ; done
echo x=$x 
#    x=1 .. but why?

x=1
echo fred | while read var ; do x=55 ; done
echo x=$x 
#    x=1  .. but why?

ベストアンサー1

正しい説明が提供されました。ジェスビリングスそしてギグドラゴンしかし、もう少し詳しく説明します。

ほとんどのシェル(Bashを含む)では、パイプの各端はサブシェルで実行されるため、シェルの内部状態(変数設定など)に対するすべての変更はパイプの対応するセグメントに制限されます。サブシェルから得られる唯一の情報は、出力内容(標準出力および他のファイル記述子の場合)と終了コード(0から255の間の数値)です。たとえば、次のコードスニペットはゼロを印刷します。

a=0; a=1 | a=2; echo $a

ksh(pdksh / mkshバリアントではなくAT&Tコードから派生したバリエーション)とzshでは、パイプラインの最後のエントリは親シェルで実行されます。 (POSIXでは両方の動作を許可します。)したがって、上記のコードスニペットは2を印刷します。オプションを設定することで、最新のbashでこの動作を得ることができますlastpipeshopt -s lastpipeインタラクティブシェルでは無効なタスク制御も使用する必要がありますset +m)。

便利なイディオムは、パイプ(またはパイプの右側のすべての項目)にwhileループの連続を含めることです。しかし、ここではwhileループは実際には非常に一般的です。

cat junk | {
  while read var ; do x=55 ; done
  echo x=$x 
}

おすすめ記事