Наиболее эффективная команда для поиска в первой строке множества файлов (windows)

699
tpdietz

Я новичок в экосистеме окон. Мне было поручено написать программу, которая будет искать несколько десятков (возможно, даже сотен) тысяч файлов для конкретной строки. Соответствующая строка представляет собой серийный номер, состоящий только из цифр и букв, длиной не более 20 символов. Прямо сейчас моя программа выполняет следующую команду:

findstr /i /m /s "searchStr" "C:\Directory\To\Search\*.*" 

Вышеприведенная команда работает, однако она слишком медленная. Файл (ы), который может содержать конкретный серийный номер, будет иметь серийный номер только в первой строке.

Кто-нибудь знает эффективный способ рекурсивного поиска в каталоге для всех файлов, которые содержат определенную строку только в первой строке?

1
Если вы используете реализацию Windows утилиты `sed` для Unix, следующая команда должна работать эффективно:` sed -sn '1s / searchStr / & / p' SearchPath \ *. * `. К сожалению, он покажет вам последовательную строку, но не имена файлов. Чтобы показать имена файлов, вы будете использовать цикл `for`, который проверяет вывод из текущего файла и показывает его имя, если это так. Но прежде чем делать все это, убедитесь, что прямой вызов достаточно быстр. AFH 9 лет назад 1
Итак, все, что делает ваша программа, это вызывает findstr? Когда вы читали ваше описание, казалось, что вы должны написать собственный код текстового поиска. Karan 9 лет назад 0
Я пытался увидеть, какие инструменты я мог бы использовать, чтобы помочь в поиске. Я мог разобрать каждый файл сам, но я думал, что встроенная «проверенная и правдивая» программа может быть более эффективной, чем то, что я придумал. Но, возможно, нет ... tpdietz 9 лет назад 0

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

2
jimbobmcgee

В PowerShell (v3.0 +), возможно ...

Get-ChildItem -Path x:\pathto\*.log ` | ForEach-Object { if (Get-Content -LiteralPath $_ -First 1 ` | Select-String -SimpleMatch -Pattern 'serialnumber')  { Write-Output $_ } } 

Различные параметры Get-ChildItemмогут возвращать подпапки и т.д .; чтобы Get-Contentполучить больше или меньше контента из файла; и Select-Stringможет выполнять более сложные сопоставления (регулярные выражения, регистр символов и т. д.).

Хороший ответ, который демонстрирует некоторые возможности Powershell; Я решил добавить ссылки на текущую документацию для [`Get-ChildItem`] (https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/get-childitem) , [`Get-Content`] (https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/get-content) и [` Select-String`] (https: //msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/select-string). simlev 7 лет назад 0
1
simlev

Я могу предложить несколько вариантов, если вам не нужно их использовать findstr, но прежде всего вы должны увидеть, можете ли вы ограничить поиск файлами определенного типа, поскольку это обязательно ускорит процесс.

  1. FileLocator Lite, по моему опыту, быстрее находит файлы и проверяет их содержимое. Обязательно заполните оба поля «имя файла» (если применимо) и «содержащий текст», а также начальный каталог.

  2. ag -il "searchStr": ag создан для скорости, поэтому он должен дать вам результаты, быстро. Не забудьте ограничить поиск по типу файла, если можете, хотя бинарные файлы по умолчанию уже пропущены. Также доступно под Cygwin .

  3. find -exec awk 'BEGIN NR==1 && /searchStr/ ' {} \;Попробуйте это, если у вас есть Cygwin или другая POSIX-подобная среда, чтобы проверить вашу идею о поиске только по первой строке. Объедините, findчтобы получить имена файлов (и, надеюсь, также отфильтровать их) и awkпроверить первую строку и напечатать ее вместе с именем файла.
  4. find | parallel 'perl -lane '\'' print "$ARGV: $_" if $. == 1 and /searchStr/i '\'' {}'Другая идея, чтобы попытаться ускорить процесс, - задействовать доступные ядра и потоки: для этого и нужна параллельная версия GNU . Этот пример спорта perl, но он делает то же самое, как awkв 3.выше. Вот разбивка команды:

    findискать файлы в текущем каталоге и его подкаталогах. Вы можете указать другой каталог, чтобы посмотреть в и шаблон файла или расширение для фильтрации на: find /cygdrive/c/Directory/To/Search -iname "*.txt".

    | «труба», т.е. передать список результатов следующей команде.

    parallel выполнить следующую команду параллельно.

    perlязык сценариев, который выделяется при манипулировании текстовыми файлами, может заменить sedили awk.

    -lane полезный набор переключателей для perl one-liners.

    '\''избежал апостроф, необходимый, так как мы уже открыли набор апостроф после parallel.

    print "$ARGV: $_"выведите имя файла ( $ARGV), двоеточие, пробел и полную строку ( $_).

    if Выполняйте предыдущую инструкцию только в том случае, если выполнены следующие условия.

    $. == 1номер строки ( $.) равен единице ( 1), т.е. мы смотрим на первую строку файла.

    and следующее условие также должно быть выполнено.

    /searchStr/iпроверяемая строка содержит текст searchStrбез учета регистра.

    '\''другой сбежавший апостроф отмечает конец perlинструкции.

    {}это будет заменено на parallelкаждое из переданных им имен файлов find.

    'конец parallelинструкции.

Обновление:awk и то и другое, и perlчтение всего файла, даже если действия связаны только с первой строкой. Решение состоит в том, чтобы явно прекратить разработку в строке 2:

find -exec awk 'BEGIN NR > 1 /searchStr/ ' {} \; find | parallel 'perl -lape '\'' exit if $. == 2; print "$ARGV: $_" if /searchStr/i '\'' {}'