1

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

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

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

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

2 ответа2

2

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

1

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

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

  2. ag -il "searchStr": ag создан для скорости, поэтому он должен давать вам результаты быстро. Не забудьте ограничить поиск по типу файла, если можете, хотя бинарные файлы по умолчанию уже пропущены. Также доступно под 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. Этот пример спортивного perl , но он делает то же самое, что и awk в 3. выше. Вот разбивка команды:

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

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

    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 '\'' {}'

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .