
職場のシステムのどこかで紛失したファイルのリストがあります。また、紛失したファイルに関連するログ エントリが含まれていると期待される、合計 46 MB の 41 個のログ ファイルが入ったフォルダーもあります。これらのログ ファイルでリスト内の値を検索するにはどうすればよいでしょうか。
リストは、ファイル拡張子なしで 1 行につき 1 つのファイルとして構成されています。ログには構造があるようですが、私はまだその構造に完全には慣れていません。ファイル名とパス、および実行された内容が含まれています。
cat *
すべてのログ ファイルを にパイプできることはわかっていますgrep
。名前が見つかったときにログ ファイルから少しコンテキストを取得するために、 と を使用すると-A
思い-B
ます。Windows で GnuWin32 を使用しているので、これを Powershell と組み合わせることができますが、そうすると、1 つのファイル名で 46 MB すべてを grep し、次のファイル名に移動するときに最初からやり直す必要があると思います。リストには 1830 個のファイルがあるため、各ファイルで最初からやり直す必要がある場合、46 MB を何度も読み取ることになるため、GB 単位の繰り返しデータを処理することになります。その方法を実行するのは非効率的と思われます。
1830 個のファイルを OR で結合した大きな正規表現を作成し、それをログに対して 1 回実行することはできると思いますが、それは実現可能でしょうか? 正規表現はほぼ 30 KB (1830 個のファイル * ファイル名の平均長約 16 文字 = 29280 バイト、さらにパイプ記号の 1830 バイト) になります。
編集:ログ フォルダー内にいて、リストが 1 つ前のフォルダーにあるときに、現在実行していることは次のとおりです。
$logs = gc *
$notfound = gc ../notfound.txt
$logs | % { $i = 0; while ($i -lt $notfound.Count) { if ($_ -contains $notfound[$i]) { echo $_ }; $i++; } } | out-file C:\discovered.txt
これは完全にPowerShellです。私はこれを高速化するためにどんなツールを使っても構いません。なぜなら、現在、すべてのログファイルを合わせると550991行あり、ファイル名は1830個あるので、このアプローチでは1,008,313,530件の比較すべてメモリ内にあるため、少なくともディスク I/O による速度低下はありません。 が真になったwhile
場合は から抜け出せるかもif
しれませんが、それでも比較を何度も行うため、最適化しても実際に効果があるかどうかはわかりません。すでに 30 分間実行されています。週末に帰宅する前に完了できれば、1 行目からアプローチを書き直してもかまいません。
答え1
正規表現を使用してログからファイル名を抽出し、それぞれがリストに含まれているかどうかを確認する方が効率的です。次のようになります。
$notfound = gc ../notfound.txt
gc * |
select-string -AllMatches '\\(?<filename>[^\\]+)\.txt' |
select -ExpandProperty Matches |
% { $_.Groups['filename'].Value } |
? { $notfound -contains $_ } |
out-file C:\discovered.txt
「\something.txt」のようなファイルを検索しています。これを変更する必要があります。
それでもまだ遅すぎて、notfound リストが非常に大きい場合は、.Net HashSet にロードする方が効率的かもしれませんが、必要がない限りそうすることはお勧めしません。