この質問の動機は「リバースのインポート」では、巨大なファイルを下から上に移動する方法について説明します。
tac file | grep whatever
またはより効率的に:
grep whatever < <(tac file)
< <(tac filename)
パイプと同じくらい速くなければなりません。
他のユーザーの興味深いコメントもたくさんあります。
私の質問:
|
これらとそしての違いは何ですか< <()
?- 一方が他よりも速いのはなぜですか?
- どちらが本当に速いですか?
- なぜ誰も提案しなかったのですか
xargs
?
ベストアンサー1
この構成<(tac file)
によってシェルが作成されます。
- 名前でパイプを作成する
- LinuxやSysVなどのシステムでは
/dev/fd
通常のパイプを使用し、/dev/fd/<the-file-descriptor-of-the-pipe>
それを名前として使用します。 - 他のシステムでは、ディスクに実際のファイルエントリを作成する必要がある名前付きパイプが使用されます。
- LinuxやSysVなどのシステムでは
- コマンドを開始
tac file
し、パイプの一端に接続します。 - コマンドラインの全体構造をパイプ名に置き換えます。
交換後のコマンドラインは次のとおりです。
grep whatever < /tmp/whatever-name-the-shell-used-for-the-named-pipe
その後、grep
実行するには標準入力(パイプなど)を読み取り、読み取り後に最初の引数を取得します。
だから最終結果は同じです...
tac file | grep whatever
...同じ2つのプログラムが実行され、パイプを使用して接続するためです。ただし、<( ... )
ビルドプロセスはより多くのステップを含み、一時ファイル(名前付きパイプ)を含めることができるため、より複雑です。
この<( ... )
構成は拡張であり、/dev/fd
標準のPOSIX bourneシェルまたはパイプをサポートしていないか、名前付きプラットフォームでは使用できません。この理由だけで考慮されている2つの選択肢は機能的に同じであるため、移植性に優れたcommand | other-command
形態がより良い選択です。
追加の畳み込みはビルド<( ... )
速度を遅くする必要がありますが、これは開始段階にのみ当てはまり、違いを簡単に測定できないと思います。
ノート:Linux SysVプラットフォームでは、< ( ... )
名前付きパイプは使用されず、代わりに通常のパイプが使用されます。通常のパイプ(実際にはすべてのファイル記述子)は特別な名前で参照できるため、/dev/fd/<file-descriptor-number
シェルはその名前をパイプ名として使用します。これにより、物理ファイルシステムで実際の一時ファイル名を使用して、実際の名前付きパイプが作成されるのを防ぎます。/dev/fd
これが最初に登場したときに実装するために使用されたトリックですが、これはksh
最適化です。この機能をサポートしていないプラットフォームでは、上記のように物理ファイルシステムの一般的な名前付きパイプが使用されます。
また参考にしてください:文法が<<( ... )
誤解を招くと説明します。実際には<( ... )
パイプ名に置き換えられ、<
この構文とは別に、すべての項目の前に付く別の文字が使用され、ファイルから入力をリダイレクトするよく知られている一般的な構文です。