リダイレクトに関連するサブシェルの優先順位は何ですか?

リダイレクトに関連するサブシェルの優先順位は何ですか?

シェル: GNU BASH

私はしばらく次のコマンドを使用してきました。

echo "$(fmt -w 50 < foo.txt)" > foo.txt

問題ありません。しかし試してみるとき:

fmt -w 50 < foo.txt > foo.txt

foo.txtファイルは空のファイルになります。これは、シェルから解析するリダイレクト演算子がサブシェルの優先順位に関連しているためだと思います。

GNU BASH マニュアルを検索しても結果が出ませんでした。マニュアルに何か抜けたのか誰か教えてもらえますか?私はこの動作の原因を理解して、それをさらに活用し、問題を引き起こす可能性があるすべての状況を理解できることを願っています。

答え1

Bashのマニュアルでは、3.7.1 簡単なコマンド拡張:

単純なコマンドを実行すると、シェルは左から右に次の拡張、割り当て、およびリダイレクトを実行します。

  1. パーサによって変数割り当てとしてマークされた単語(コマンド名の前の単語)とリダイレクトは、後で処理するために保存されます。
  2. 変数の割り当てやリダイレクトではない単語は拡張されます。シェル拡張)。拡張後に残りの単語がある場合、最初の単語はコマンド名として扱われ、残りの単語は引数として扱われます。
  3. リダイレクトは上記のように行われます(参照:リダイレクト)。
  4. 各変数の割り当て後のテキストは、=変数に割り当てられる前に、チルダ拡張、パラメータ拡張、コマンド置換、算術拡張、および引用符の削除を経ます。

コマンド置換は、(2) で発生する拡張の 1 つであり、(3) で拡張後にリダイレクトが発生します。これは、サブシェルとは無関係であり、純粋にシェルが操作を実行する順序によるものです。(fmt -w 50 < foo.txt) > foo.txt空のファイルも作成されます。

答え2

人々が利用できるsponge公益事業:

fmt -w 50 < foo.txt | sponge foo.txt

原文に関する注意事項:

echo "$(fmt -w 50 < foo.txt)" > foo.txt
  1. 最初に実行されるのは、fmt出力がひもつまり二重引用符で囲まれた内容です。fmt完了するまで他のことは起こりません。

  2. echo文字列を次に印刷します。標準出力

  3. その間、echo出力は>次にリダイレクトされます。foo.txt

ステップ2と3はほぼ同時に発生します。

元のコードには実際に問題があります。コマンドラインに長さ制限。入力したらfoo.txt非常に大きく、特に長さが大きい場合、getconf ARG_MAXコマンドechoは失敗または不完全な結果を提供します。

関連情報