如何使用多个AND模式运行grep?


86

我想在模式之间使用隐式AND进行多模式匹配,即等效于在序列中运行多个抓取:

grep pattern1 | grep pattern2 | ...

那么如何将其转换为类似的东西呢?

grep pattern1 & pattern2 & pattern3

我想使用单个grep,因为我正在动态构建参数,因此所有内容都必须放在一个字符串中。使用filter是系统功能,而不是grep,因此不是它的参数。


请勿将此问题与以下内容混淆:

grep "pattern1\|pattern2\|..."

这是一个OR多模式匹配。



Answers:


78

agrep 可以使用以下语法:

agrep 'pattern1;pattern2'

使用GNU grep,在使用PCRE支持构建时,您可以执行以下操作:

grep -P '^(?=.*pattern1)(?=.*pattern2)'

astgrep

grep -X '.*pattern1.*&.*pattern2.*'

(添加.*S作为<x>&<y>匹配同时匹配的字符串<x><y> 准确a&b将不会匹配,因为没有这样的字符串,可以两个a,并b在同一时间)。

如果模式不重叠,您也可以执行以下操作:

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

最好的便携式方法可能awk就是已经提到的:

awk '/pattern1/ && /pattern2/'

sed

sed -e '/pattern1/!d' -e '/pattern2/!d'

请注意,所有这些将具有不同的正则表达式语法。


1
agrep语法不是为我工作......这版本是它引入了?
拉曼

1992年的 @Raman 2.04已经有了它。我没有理由相信它从一开始就不存在。agrep可以在glimpse / webglimpse中找到更新的(1992年之后)版本。可能您有不同的实现。我曾经为AST-grep的版本错误,虽然,该选项增强的正则表达式-X,没有-A
斯特凡Chazelas

@StéphaneChazelas谢谢,我agrep在Fedora 23上有0.8.0。这似乎与agrep您所引用的有所不同。
拉曼

1
@Raman,您的声音听起来像TREagrep
斯特凡Chazelas

2
@Techiee,或者只是awk '/p1/ && /p2/ {n++}; END {print 0+n}'
斯特凡Chazelas

19

您未指定grep版本,这一点很重要。一些正则表达式引擎允许使用“&”按AND将多个匹配分组,但这是非标准且不可移植的功能。但是,至少GNU grep不支持此功能。

OTOH您可以简单地用sed,awk,perl等替换grep(按重量增加顺序列出)。使用awk,命令看起来像

awk'/ regexp1 / && / regexp2 / && / regexp3 / {打印; }'

可以轻松地在命令行中指定它。


3
只需记住,awk使用的是ERE,例如等价的grep -E,而不是普通grep使用的BRE 。
2012年

3
awk的正则表达式称为 ERE,但实际上它们有点特质。这里可能是比任何人都更关心的详细信息:wiki.alpinelinux.org/wiki/Regex
dubiousjim 2012年

谢谢grep 2.7.3(openSUSE)。我投票给你,但是我将让问题待一会儿,也许grep有一些技巧(不是我不喜欢awk,只是知道更多更好)。
greenoldman 2012年

2
默认操作是打印匹配的行,因此该{ print; }零件在这里并不是真正必需或有用的。
Tripleee '17

7

如果patterns每行包含一个模式,则可以执行以下操作:

awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -

或匹配子字符串而不是正则表达式:

awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -

要在输入patterns为空的情况下打印所有输入而不是不输入任何行,请替换NR==FNRFILENAME==ARGV[1],或替换为ARGIND==1in gawk

这些函数打印STDIN的行,其中包含指定为参数的每个字符串作为子字符串。ga代表grep all,gai忽略大小写。

ga(){ awk 'FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1' <(printf %s\\n "$@") -; }
gai(){ awk 'FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1' <(printf %s\\n "$@") -; }

7

这不是一个很好的解决方案,但是说明了一个很酷的“技巧”

function chained-grep {
    local pattern="$1"
    if [[ -z "$pattern" ]]; then
        cat
        return
    fi    

    shift
    grep -- "$pattern" | chained-grep "$@"
}

cat something | chained-grep all patterns must match order but matter dont

1
二者必选其一chained-grep()function chained-grep而不是function chained-grep()unix.stackexchange.com/questions/73750/...
nisetama

3

git grep

以下是git grep使用布尔表达式组合多个模式的语法:

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3

上面的命令将同时打印匹配所有模式的行。

--no-index 搜索当前目录中不受Git管理的文件。

检查man git-grep帮助。

也可以看看:

有关“ 或”运算,请参见:


1

ripgrep

这是使用示例rg

rg -N '(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)' file.txt

它是最快的grepping工具之一,因为它建立在Rust的正则表达式引擎之上,该引擎使用有限自动机,SIMD和积极的文字优化来使搜索变得非常快。

另请参阅GH-875上的相关功能要求。


1

这是我的看法,适用于多行单词:

使用find . -type f后跟尽可能多
-exec grep -q 'first_word' {} \;
的关键字
-exec grep -l 'nth_word' {} \;

-q
-l带有匹配项的安静/无声 显示文件

以下返回文件名列表,其中包含单词“ rabbit”和“ hole”:
find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;


-2

要查找所有单词(或模式),可以在FOR loop中运行grep。这里的主要优点是从正则表达式列表中进行搜索

用一个真实的例子编辑我的答案:

# search_all_regex_and_error_if_missing.sh 

find_list="\
^a+$ \
^b+$ \
^h+$ \
^d+$ \
"

for item in $find_list; do
   if grep -E "$item" file_to_search_within.txt 
   then
       echo "$item found in file."
   else
       echo "Error: $item not found in file. Exiting!"
       exit 1
   fi
done

现在让我们在此文件上运行它:

啊啊啊啊啊啊

aa

bbbbbbbbb

阿巴巴巴巴巴

ccccccc

dsfsdf

bbbb

ccddd

a

a

# ./search_all_regex_and_error_if_missing.sh

啊啊啊啊啊

在文件中找到^ a + $。

bbbbbbbbbb bbbb

在文件中找到^ b + $。

啊啊啊啊啊啊

在文件中找到^ h + $。

错误:在文件中找不到^ d + $。退出!


1
您的逻辑有误-我要求ALL运算符,您的代码可以用作OR运算符,而不是AND。顺便说一句。因为(OR)是问题中给出的更简单的解决方案。
greenoldman

@greenoldman逻辑很简单:for将在列表中的所有单词/模式上循环,如果在文件中找到它,则将其打印出来。因此,如果您不需要采取行动以防找不到单词,只需删除else。
Noam Manos

1
我理解您的逻辑以及我的问题-我在问AND运算符,这意味着如果文件与模式A和模式B以及模式C和... AND匹配,则文件仅是肯定命中。模式A或模式B或...现在看到区别了吗?
greenoldman

@greenoldman不确定为什么您认为此循环不检查所有模式的AND条件?因此,我用一个真实的示例编辑了我的答案:它将在文件中搜索列表的所有正则表达式,并且在第一个缺少的正则表达式上-会错误退出。
Noam Manos

您将它摆在眼前,在执行第一个比赛后就拥有正面比赛。您应该“收集”所有结果并对其进行计算AND。然后,您应该重写脚本以在多个文件上运行-然后,也许您意识到问题已经得到回答,并且您的尝试没有带来任何好处,对不起。
greenoldman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.