ディレクトリに文字 "a"で始まる100個のファイルがあるとします。
grep <some string> a*
端末で実行すると、シェルはこれをどのように処理しますか?
正規表現を展開し、aで始まるすべてのファイルのリストを取得し、各ファイルを順番にgrepしますか?それとも別の方法がありますか?
上記の「a」で始まるファイル名の配列があるとしましょう。 forループを作成してシェルスクリプトまたはacプログラムで直接反復を実行すると、時間がかかりませんか?
答え1
a*
まず、少し問題です。一般的なシェル構文などの文字列は、正規表現とは異なる動作をするglobです。
通常、シェルインタプリタ(bashなど)は、文字列をパターンにa*
一致する各ファイル名のリストに展開しますa*
。これはコマンドライン引数の一部になります。一つ(プログラマの場合、grep
すべての拡張語は別々の文字列引数として提供されますargv
)main
。その後、コマンドはgrep
選択した方法で引数を解析し、grep
それをファイル名、オプション、オプションパラメータ、正規表現などとして解釈し、適切なアクションを実行します。すべてが順次発生します(私が知る限り、マルチスレッドを使用した実装はありませんgrep
)。
同じタスクを実行するためにシェルスクリプトでループを実装した場合、次の理由で上記のプロセスよりもほぼ遅くなります。各ファイルに対して新しいgrepプロセスを作成すると、不要なプロセス生成のオーバーヘッドが確実に遅くなります。シェルスクリプトから直接引数リストを作成して単一のgrep
インスタンスを使用する場合は、シェルコマンドを(bashを介して)解釈する必要があり、追加のコードレイヤが追加されるため、シェルで実行するすべての操作はまだ遅くなります。そして、コンパイルされたコードでbashが内部的に速くすることを再実装するだけです。
Cで直接書くと、最初の段落で説明したプロセスと同様のパフォーマンスを簡単に得ることができますが、特定の最適化を探索しなくても時間を正当化するのに十分なパフォーマンスを向上させる可能性は低くなります。機械性能でなければ、移植性が犠牲になる。たぶんランダムに並列化できるバージョンを作成しようとするかもしれませんが、grep
CPUバインディングよりもI / Oバインディングに依存しているので、それは役に立ちません。グローバル拡張とgrepは、ほとんどの「一般的な」用途には「十分に高速です」。
答え2
はい、ファイルリストに展開され、結果リストをプログラムに提供しますgrep
。少なくともそれはman bash
サブセクションで言ったものです。パス名拡張。
grep <some_string> a
述べたように、単純なケースで拡張を使用する別の方法があります。押す前に*
、によるとESC。これにより、コマンドラインで一致するファイルのリストが展開されるため、を押す前にリストが正しいことを確認できますEnter。
質問の2番目の部分は状況によって異なります。各ファイルに対して順番に grep を実行する for ループを作成すると、grep プログラムが一度は実行されず、各ファイルに対して 1 回実行されるため、間違いなく遅くなります。しかし何はい特定のことがあることを覚えておくことが重要です。限界コマンドライン引数の拡張長を使用できますが、通常はかなり長いです。これを見るために試してみてくださいgrep adasdsadf /usr/*/*/* >/dev/null
。