4

説明が欲しい楽しい小さな bash ティーザー。

私が持っている2つのループ構造は同一ですが、明らかにそうではありません。whileループを実行するときのパイプとリダイレクトにはいくつかの違いがあるようです。

入力ファイル

このサンプル ファイルvalues.txtが次の内容で呼び出されるとします。

1
2
3
4
5
6

while への配管

$ value=0; cat values.txt | while read var; do value=`expr $value + $var`; done
$ echo $value
0

while へのリダイレクト

$ value=0; while read var; do value=`expr $value + $var`; done < values.txt
$ echo $value
21

簡単に言うと、明らかに最初のバージョンでは、whileループの各反復は として効果的に実行さ()れ、2 番目のバージョンでは、各反復は次のように反復されます。{}

()問題はとの違いではありません{}。私の質問は、ループの動作にこの違いが生じる原因は何ですか?while

それらが異なる動作をするべき論理的な理由はありますか、それとも互換性の理由で変更できなかったのは、早い段階で行われた悪い選択でしたか? パイプして動作whileを取得することは可能{}ですか?

4

1 に答える 1

7

これは既知の問題であり、ここで詳しく説明されています: http://mywiki.wooledge.org/BashFAQ/024

最も説明的な部分を引用するには:

この状況では、さまざまなシェルがさまざまな動作を示します。

  • BourneShellは、パイプラインまたはリダイレクト演算子 ('<', '>') を使用して単純なコマンドをリダイレクトする以外に、何か (ループ、ケースなど) の入力または出力を行うときにサブシェルを作成します。
  • BASHは、ループがパイプラインの一部である場合にのみ、新しいプロセスを作成します。
  • KornShell は、ループがパイプラインの一部である場合にのみ作成し、ループがパイプラインの最後の部分である場合は作成しません。
  • POSIX ではbash の動作が指定されていますが、拡張機能として、パイプラインの一部またはすべての部分をサブシェルなしで実行できます (したがって、KornShell の動作も許可されます)。

最後の質問について: はい、特定のシェルでは可能です。また、bash >=4.2 を使用している場合にのみ bash で可能です。コードの前に、次のコードを使用してジョブ制御を無効にし、lastpipe オプションを有効にします。set +m; shopt -s lastpipe

于 2012-09-16T07:39:33.637 に答える