Как сопоставить все файлы, содержащие слово1 И слово2 в разных строках, с ag или rg (PCRE/Rust regex)
У меня длинный список сгенерированных отчетов, которые я хочу отфильтровать. Отчет выглядит примерно так:
Report Name
Report Date
Blah blah blah
Blah: WORD1
Blah blah
blah blah: WORD2
blah blah
Я пытаюсь использовать ag (PCRE regex) или rg (rust regex) и найти все файлы, которые содержат WORD1 и WORD2 в разных местах файла (содержит новую строку).
Я уже искал SX и нашел эти, которые не работали:
> ag (?=.*WORD1)(?=.*WORD2)
> ag (?=.*WORD1)((.|\n)*)(?=.*WORD2)
ОБНОВИТЬ
Как отметил @WiktorStribiżew, ag использует PCRE. Извините за ошибку.
мой ожидаемый результат:
blah blah: WORD2
или просто список подходящих файлов.
PS в настоящее время мне удалось использовать это:
> ag "WORD2" $(ag -l "WORD1")
4 ответа
Вы можете использовать шаблон PCRE с ag
:
(?s)^(?=.*WORD1)(?=.*WORD2).*\n\K(?-s).*WORD2
Смотрите демо-версию регулярного выражения.
Детали:
(?s)
- модификатор DOTALL ON (.
соответствует символу перевода строки)^
- начало строки(?=.*WORD1)
- должно бытьWORD1
где-то в строке(?=.*WORD2)
- должно бытьWORD2
где-то в строке.*
- любые 0+ символов, как можно больше, до последнего появления последующих подшаблонов (если вы используете ленивый*?
квантор,.*?
будет соответствовать 0+ символов как можно меньше до первого вхождения последующих подшаблонов)\n
- новая строка\K
- оператор сброса совпадений, отбрасывающий текущий сопоставленный текст(?-s)
- Режим DOTALL отключен (.
не соответствует разрывам строк).*WORD2
- любые 0+ символов, кроме символов разрыва строки, как можно больше, а затемWORD2
,
Вопрос упоминает эту модель, которая работает:
ag "WORD2" $(ag -l "WORD1")
Но только WORD2
будет выделен цветом. Я предпочитаю:
ag 'WORD1|WORD2' --passthru -C3 $(ag -l "WORD1" $(ag -l "WORD2"))
Это дает три строки по обе стороны от матчей и выделяет оба WORD1
а также WORD2
,
function agmw() {
args=("$@")
qs="ag -l $1"
for i in {2..$#}; do
qs="$qs | xargs -r ag -l '${args[$i]}'"
done
argarr="$1"
for i in {2..$#}; do
argarr="$argarr|${args[$i]}"
done
qs="$qs | xargs -r ag '$argarr'"
echo $qs
ag '$argarr'
bash -c $qs
}
agmw hello world #seacrh привет и мир во всех файлах
PS в настоящее время мне удалось использовать это:
ag "WORD2" $(ag -l "WORD1")
Это, безусловно, самый простой способ сделать это. Инструменты, о которых вы говорите, изначально ориентированы на строки, и вы хотите сопоставить разные строки в одном файле.
Если вы используете ack, он имеет -x
оператор, который позволяет вам сделать ack -l WORD1 | ack -x WORD2
что в основном то же самое, что ack -l WORD1 | xargs ack WORD2
без необходимости вводить xargs
в трубопровод.