Bash grep -P со списком регулярных выражений из файла - PullRequest
0 голосов
/ 16 апреля 2020

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

Мой подход для одиночный тест регулярного выражения:

find unsorted_test/. -type f -print0 |
    xargs -0 grep -Pazo '(?P<message>User activity exceeds.*?\:\s+(?P<user>.*?))\s' |
    tr -d '\000' |
    fgrep -a unsorted_test |
    sed 's/^.*unsorted/unsorted/' |
    cut -d: -f1 > matched_files_unsorted_test000.txt ;
wc -l matched_files_unsorted_test000.txt

find | xargs позволяет обойти ошибку "слишком много аргументов" для grep

grep -Pazo это та, которая делает тяжелую работу -P для PCRE Регулярное выражение -a должно гарантировать, что файлы читаются как текст, а -z -o просто потому, что оно не работает иначе с файловой базой, которую у меня есть

tr -d '\000', чтобы убедиться, что выходные данные не являются двоичными

fgrep -a - получить только строку с именем файла

sed - противодействовать удивительной привычке grep добавлять конечные строки друг к другу (в основном удаляет все в строке перед filepath)

cut -d: -f1 обрезает только путь к файлу

wc -l считает размер результирующего списка файлов

Результатом является файл с 10k + строками как это: unsorted/./2020.03.02/68091ec4-cf04-4843-a4b2-95420756cd53, что я и хочу в итоге.

Очевидно, что это не очень хорошо, но это прекрасно работает для чего-то, сделанного из палочек и грязи. Моя главная цель здесь - проверить понятия и регулярные выражения, а не рассчитывать на дальнейшее масштабирование или что-то еще.

Итак, поскольку grep -P не поддерживает параметр -f, я попытался использовать while read l oop:

(while read regexline ;
    do echo "$regexline" ;
    find unsorted_test/. -type f -print0 |
    xargs -0 grep -Pazo "$regexline" |
    tr -d '\000' |
    fgrep -a unsorted_test |
    sed 's/^.*unsorted/unsorted/' |
    cut -d: -f1 > matched_files_unsorted_test000.txt ;
    wc -l matched_files_unsorted_test000.txt |
    sed 's/^ *//' ;
done) < regex_1.txt

И, как вы можете себе представить, - это потрясающе не получается: ноль соответствует всему.

Я экспериментировал с кавычками в grep, с l oop наберите et c. Ничего.

Любая помощь с текущим кодом или предложения о том, как это сделать в противном случае, очень ценится. Спасибо.

PS Да, я пробовал pcregrep, но он возвращает ноль совпадений даже для одного шаблона. Не знаю почему.

1 Ответ

0 голосов
/ 16 апреля 2020

Вы можете сделать это, что будет невозможно медленно:

find unsorted_test/. -type f -print0 |
while IFS= read -d '' -r file; do
     while IFS= read -r regexline; do
        grep -Pazo "$regexline" "$file"
    done < regex_1.txt
done |
tr -d '\000' | fgrep -a unsorted_test... blablabla

Или для каждой строки:

find unsorted_test/. -type f -print0 |
while IFS= read -d '' -r file; do
    while IFS= read -r line; do
         while IFS= read -r regexline; do
             if grep -Pazo "$regexline" <<<"$line"; then
                  break
             fi
        done < regex_1.txt
done |
tr -d '\000' | fgrep -a unsorted_test... blablabl

Или, может быть, с xargs.

Но я верю просто объедините регулярные выражения из файла с помощью |:

find unsorted_test/. -type f -print0 |
{
    regex=$(< regex_1.txt paste -sd '|')
    # or maybe with braces
    # regex=$(< regex_1.txt sed 's/.*/(&)/' | paste -sd '|')
    xargs -0 grep -Pazo "$regex"
} |
....

Примечания:

  • Чтобы прочитать строки из файла, используйте IFS= read -r line. Параметр -d '' для read имеет синтаксис bash.
  • Строки с пробелами, вкладками и комментариями только после игнорирования канала. Вы можете просто поместить свои команды в отдельные строки.
  • Использовать grep -F вместо устаревших fgrep.
...