Ищите много разных строк в разных лог файлах?

750
Corey Ogburn

У меня есть список файлов, которые пропали где-то в нашей системе на работе. У меня также есть папка, содержащая 41 файл журнала, в который добавляется до 46 МБ, и, надеюсь, в нем есть записи, относящиеся к отсутствующим файлам. Как я могу grep эти файлы журнала для любого значения в моем списке?

Список структурирован как один файл на строку без расширения файла. Журналы, кажется, имеют структуру, но я пока не совсем знаком с этой структурой. Он содержит имена файлов и пути, а также то, что с ним было сделано.

Я знаю, что могу cat *все файлы журнала и передать его grep. Я, вероятно, буду использовать -Aи -Bдля получения небольшого контекста из файлов журналов, когда имя будет найдено. Я использую GnuWin32 на окнах, чтобы я мог связать это с Powershell, но я думаю, что для этого потребуется, чтобы одно имя файла заняло все 46 МБ, а когда я перехожу к следующему имени файла, я начинаю заново. У меня есть 1830 файлов в списке, поэтому, если мне придется начинать все сначала, я буду читать 46 МБ столько раз, что буду иметь дело с ГБ повторяющихся данных. Это кажется неэффективным.

Я полагаю, я мог бы создать большое регулярное выражение из файлов 1830 года или собрать вместе и запустить его один раз для журналов, но возможно ли это? Регулярное выражение будет почти 30 КБ (1830 файлов * средняя длина имени файла около 16 символов = 29280 байт, не говоря уже о 1830 байтах символов канала).

Изменить: вот что я делаю сейчас, когда я нахожусь в папке журналов, и список находится на одну папку назад:

$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 сравнений . Это все в памяти, так что, по крайней мере, у меня нет дискового ввода-вывода, замедляющего меня. Я мог бы вырваться из ситуации, whileесли это ifстанет правдой, но я все еще собираюсь сделать так много сравнений, что я не уверен, что оптимизация действительно принесет пользу. Это уже работает в течение получаса. Я в порядке с переписыванием моего подхода от линии 1, если я могу сделать это прежде, чем я уеду домой на выходные.

0
Если вам удастся удержать 46 МБ в памяти, повторное чтение не является проблемой. Hagen von Eitzen 10 лет назад 0
@HagenvonEitzen Это возможно. Corey Ogburn 10 лет назад 0

1 ответ на вопрос

0
dangph

It would be more efficient to pull the filenames out the logs via a regular expression and see if each of those is in your list. It could look something like this:

$notfound = gc ../notfound.txt gc * | select-string -AllMatches '\\(?<filename>[^\\]+)\.txt' | select -ExpandProperty Matches | % { $_.Groups['filename'].Value } | ? { $notfound -contains $_ } | out-file C:\discovered.txt 

I am searching for files that look like "\something.txt". You will have to change that.

If it's still too slow and your notfound list is very large, then it might be more efficient to load it into a .Net HashSet, but I wouldn't do that unless needed.