シェル(bashなど)はワイルドカードパターンをどのように展開しますか?


9

ディレクトリに、文字「a」で始まる100個のファイルがあると仮定します。

grep <some string> a*端末から行う場合、シェルはこれをどのように処理しますか?

それは正規表現を拡張し、aで始まるすべてのファイルのリストを取得し、それらのファイルのそれぞれで順次grepを取得しますか?それとも他の方法がありますか?

上記のファイル名の配列が「a」で始まると仮定します。forループを記述し、シェルスクリプトまたはacプログラムで自分で反復を実行すると、時間がかかりますか?


7
ところで、これglobは正規表現ではありません。大きな違い。
アーロンD.マラスコ2011

回答:


8

まず、nitpick:a*通常のシェル構文のような文字列は、正規表現とは異なる働きをするグロブです。

高レベルの概要では、シェルインタープリター(bashなど)は、文字列a*を、patternに一致するすべてのファイル名のリストに展開しますa*。これらは、コマンドラインパラメータの一部になり、の単一のインスタンスになりますgrep(プログラマーの場合、展開されたすべての単語は個別の文字列としてのargv引数に入れられますmain)。grepその後、その単一のコマンドが選択した方法で引数を解析し、grepそれらの引数をファイル名、オプション、オプション引数、正規表現などとして解釈し、適切なアクションを実行します。すべてが順番に発生します(AFAIKのgrep実装では複数のスレッドを使用していません)。

シェルスクリプトにループを実装して同じことを行う場合、以下の理由により、上記のプロセスよりも遅くなることがほぼ保証されています。ファイルごとに新しいgrepプロセスを生成すると、プロセス作成のオーバーヘッドが不必要に増加するため、確実に遅くなります。シェルスクリプトで引数リストを自分で作成し、の単一のインスタンスを使用した場合、grepシェルコマンドは(bashで)解釈する必要があるため、シェルで実行するすべての処理が遅くなり、コードの追加レイヤーが追加されます。コンパイル済みコードの内部で、bashがすでに高速に実行していたことを再実装するだけです。

Cで自分で書く場合、最初の段落で説明したプロセスと同等のパフォーマンスを簡単に得ることができますが、現在のgrep / bash実装よりも十分なパフォーマンス向上を達成して時間を正当化することはできません。マシン固有のパフォーマンスの最適化について調べたり、移植性を犠牲にすることなく費やしました。多分、の任意に並列化可能なバージョンを考え出すことができgrepますが、CPUバウンドよりもI / Oバウンドになる可能性が高いため、それでも役に立たない場合があります。Globの拡張とgrepは、ほとんどの「通常の」目的にはすでに「十分に高速」です。


非常に詳細な回答をありがとう。実際、gzip圧縮されたファイルをgrepする必要があります(それぞれ数GB)。それらのファイルのリストがあります。これらのファイルに一致するように正規表現(複雑)を構築するか、既知のリストを反復処理して、それらのそれぞれに対してgrepを実行する(簡単)かの選択肢があります。したがって、パフォーマンスに関する懸念。
ハリススキー2011

してみてくださいzcatzgrep。それらを1つずつ解凍する必要はありません
jw013

はい、もちろん。私はzgrepを使用しています。
ハリススキー、2011

6

はい、それはファイルのリストに展開し、結果のリストをgrepプログラムにフィードします。少なくともman bash、サブセクション「パス名の展開」でそれが述べられています。

あなたが言及するように、単純なケースで拡張を使用する別の方法があります:書き込みgrep <some_string> aを押す前にを*押しESCます。これにより、一致するファイルのリストがコマンドラインの右側に展開されるので、を押す前にリストに問題がないことを確認できますEnter

質問の2番目の部分については、状況によって異なります。各ファイルでgrepを順番に実行するforループを作成する場合、grepプログラムは1回ではなく、ファイルごとに1回実行されるため、確実に遅くなります。しかし、何心に留めておくことは重要ことは一定の存在であるということである限界、それは一般的に非常に高いですが、あなたが使用できるコマンドライン引数の拡大長さには、。それを確認するには、を試してくださいgrep adasdsadf /usr/*/*/* >/dev/null


2
ESC+*ESC+*ドットファイル(で始まる名前)を挿入します.が、の展開は設定に*依存するため、bashに*を展開させるのとまったく同じではありませんdotglob shopt。グロブを展開および挿入するキーシーケンスはC-x *デフォルトであり、readlineコマンドにマッピングされますglob-expand-word
jw013、2011

1
@ jw013情報ありがとうございます!a*拡張の場合は変更されないようですが、より広い範囲で重要です。
rozcietrzewiacz 2011

2
zsh注:展開可能なパラメーター(グロブパターン、ブレース展開、コマンド置換など)でタブキーを押すだけで展開されます。
ステファン・ヒメネス

@ jw013実際、私はC-xショートカットをテストしただけで、(bashを使用して)システム上のファイルのリストを展開しませ
rozcietrzewiacz

1
@roz正解-とにかくこれを使うことはほとんどありません。(どちらかと言えば)違いを指摘したかっただけです:)。 C-x *ファイル名だけを行うグロブだけを実行しますが、可能なすべての補完の場合と同様に、Esc *実際にはそれがより多くのinsert-completionsことを実行します。つまりEsc *、空のコマンドラインでを使用する$PATHと、たとえば、すべての実行可能ファイルの名前がに挿入されます。
jw013、2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.