如何使用 ag 或 rg(PCRE/Rust 正则表达式)匹配不同行中包含 word1 和 word2 的所有文件
how to match all files containing word1 AND word2 across different lines with ag or rg (PCRE/Rust regex)
我有一长串要过滤的已生成报告。报告是这样的:
Report Name
Report Date
Blah blah blah
Blah: WORD1
Blah blah
blah blah: WORD2
blah blah
我正在尝试使用 ag(PCRE 正则表达式)或 rg(rust 正则表达式)并在文件的不同位置(包含新行)查找包含 WORD1 和 WORD2 的所有文件。
我已经搜索过 SX,发现这些都不起作用:
> ag (?=.*WORD1)(?=.*WORD2)
> ag (?=.*WORD1)((.|\n)*)(?=.*WORD2)
更新
正如@WiktorStribiżew 所指出的,ag 使用 PCRE。抱歉弄错了。
我的预期输出是:
blah blah: WORD2
或者只是匹配文件的列表。
p.s。目前我已经设法使用这个:
> ag "WORD2" $(ag -l "WORD1")
您可以使用 ag
:
的 PCRE 模式
(?s)^(?=.*WORD1)(?=.*WORD2).*\n\K(?-s).*WORD2
参见regex demo。
详情:
(?s)
- DOTALL 修饰符开启(.
匹配换行字符)
^
- 字符串开头
(?=.*WORD1)
- 字符串中某处必须有 WORD1
(?=.*WORD2)
- 字符串中某处必须有 WORD2
.*
- 任何 0+ 个字符,尽可能多,直到后续子模式的最后一次出现(如果使用惰性 *?
量词,.*?
将匹配0+ 个字符尽可能少,直到 first 出现后续子模式)
\n
- 一个换行符
\K
- 匹配重置运算符丢弃当前匹配的文本
(?-s)
- DOTALL 模式禁用(.
不匹配换行符)
.*WORD2
- 除换行字符外的任何 0+ 个字符,尽可能多,然后是 WORD2
.
p.s. currently I've managed to using this: ag "WORD2" $(ag -l "WORD1")
这当然是最简单的方法。您正在谈论的工具本质上是面向行的,您希望匹配同一文件中的不同行。
如果你使用 ack,它有 -x
运算符,可以让你做 ack -l WORD1 | ack -x WORD2
这基本上与 ack -l WORD1 | xargs ack WORD2
相同,而不必将 xargs
引入管道。
问题提到了这个模式,有效:
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 "
for i in {2..$#}; do
qs="$qs | xargs -r ag -l '${args[$i]}'"
done
argarr=""
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 hello and world 所有文件
我有一长串要过滤的已生成报告。报告是这样的:
Report Name
Report Date
Blah blah blah
Blah: WORD1
Blah blah
blah blah: WORD2
blah blah
我正在尝试使用 ag(PCRE 正则表达式)或 rg(rust 正则表达式)并在文件的不同位置(包含新行)查找包含 WORD1 和 WORD2 的所有文件。
我已经搜索过 SX,发现这些都不起作用:
> ag (?=.*WORD1)(?=.*WORD2)
> ag (?=.*WORD1)((.|\n)*)(?=.*WORD2)
更新
正如@WiktorStribiżew 所指出的,ag 使用 PCRE。抱歉弄错了。
我的预期输出是:
blah blah: WORD2
或者只是匹配文件的列表。
p.s。目前我已经设法使用这个:
> ag "WORD2" $(ag -l "WORD1")
您可以使用 ag
:
(?s)^(?=.*WORD1)(?=.*WORD2).*\n\K(?-s).*WORD2
参见regex demo。
详情:
(?s)
- DOTALL 修饰符开启(.
匹配换行字符)^
- 字符串开头(?=.*WORD1)
- 字符串中某处必须有WORD1
(?=.*WORD2)
- 字符串中某处必须有WORD2
.*
- 任何 0+ 个字符,尽可能多,直到后续子模式的最后一次出现(如果使用惰性*?
量词,.*?
将匹配0+ 个字符尽可能少,直到 first 出现后续子模式)\n
- 一个换行符\K
- 匹配重置运算符丢弃当前匹配的文本(?-s)
- DOTALL 模式禁用(.
不匹配换行符).*WORD2
- 除换行字符外的任何 0+ 个字符,尽可能多,然后是WORD2
.
p.s. currently I've managed to using this:
ag "WORD2" $(ag -l "WORD1")
这当然是最简单的方法。您正在谈论的工具本质上是面向行的,您希望匹配同一文件中的不同行。
如果你使用 ack,它有 -x
运算符,可以让你做 ack -l WORD1 | ack -x WORD2
这基本上与 ack -l WORD1 | xargs ack WORD2
相同,而不必将 xargs
引入管道。
问题提到了这个模式,有效:
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 "
for i in {2..$#}; do
qs="$qs | xargs -r ag -l '${args[$i]}'"
done
argarr=""
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 hello and world 所有文件