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

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

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

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

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

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

решение1

В 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выполнять более сложные сопоставления (регулярные выражения, с учетом регистра и т. д.).

решение2

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

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

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

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

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

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

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

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

    -laneполезный набор ключей для однострочных программ на Perl.

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

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

    ifвыполнять предыдущую инструкцию только при соблюдении следующих условий.

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

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

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

    '\''Еще один экранированный апостроф отмечает конец perlинструкции.

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

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

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

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

Связанный контент