如何在严格排除的匹配子集中有效地列出匹配的内容和文件名?



这个看似简单,我想我错过了一些明显的东西......但是我一直无法找到一种有效的方法来生成以下列表:

  1. 文件名
  2. 与模式匹配的内容

。在我通过单行排除子模式(捕获)消除大多数匹配的情况下。

在大约~1,300感兴趣的代码文件中,~1,000包含{brandedTerm},基于以下检查:

可能匹配的感兴趣的代码文件数(基于扩展名):
( printf "%sn" $( find . -type f -name "*.{extension}" ) )| wc -l

代码文件数...包含术语:
( printf "%sn" $( find . -type f -name "*.{extension}" -exec grep -l "{brandedTerm}" {} ; ) )| wc -l

问题是这些匹配中的大多数都是我不关心的子模式,因为它们是注释或枚举名称等。 我试图寻找的是字符串中{brandedTerm}的使用,以修改/混淆研究的少数用例。

我几乎可以实现我想要的w/:
find . -type f -name "*.{extension}" -exec grep "{brandedTerm}" {} ; | sed -e '/{exclusion_pattern_1}/d; ... /{exclusion_pattern_k}/d'

。其中{exclusion_pattern_1}、...、{exclusion_pattern_k}表示与我不关心的子匹配项(大多数匹配项)匹配的模式。

这将在排除后打印匹配项本身(2.)。 唯一的问题是没有列出在 (1.中找到这些排除后匹配的文件;鉴于我希望编辑这些比赛,这是必要的。

事实证明,我摆弄过的大多数途径(循环匹配文件并连接文件名/匹配,然后排除重新搜索应用排除的匹配模式)已被证明是繁重而缓慢的。

我认为有一些更简单的方法来查找文件并打印带有排除项的匹配内容,在这种情况下:

  1. 排除项代表大多数匹配项
  2. 许多排除模式适用。

思潮?

(另外,如果有重复的,请告诉我...在这个特定的上下文中找不到任何东西,但awk/sed都很好,所以我很谨慎,我没有点击正确的搜索短语来找到一些预先存在的答案。

使用 GNU awk,这将找到当前目录中扩展名ext的所有文件,这些文件包含正则表达式brandedTerm,但不包含exclude1exclude2

awk '/brandedTerm/{f=1} /exclude1/ || /exclude2/{g=1; nextfile} ENDFILE{if (f && !g) print FILENAME; f=0;g=0}' *.ext

对于那些喜欢的人,分布在多行上的相同命令如下所示:

awk '/brandedTerm/{
f=1
}
/exclude1/ || /exclude2/{
g=1
nextfile
}
ENDFILE{
if (f && !g)
print FILENAME
f=0
g=0
}' *.ext

递归搜索

要将上述内容应用于当前目录中的所有文件,并以递归方式通过其以.ext结尾的子目录,请使用find

find . -type f -name '*.ext' -execdir awk '/brandedTerm/{f=1} /exclude1/ || /exclude2/{g=1; nextfile} ENDFILE{if (f && !g) print FILENAME; f=0;g=0}' {} +

工作原理

Awk 将隐式逐行循环参数列表中的每个文件。

  • /brandedTerm/{f=1}

    如果当前行与正则表达式brandedTerm匹配,则将f设置为 1 (true)。

  • /exclude1/ || /exclude2/{g=1; nextfile}

    如果当前行包含正则表达式exclude1exclude2,则将g设置为 1 (true) 并跳过文件的其余部分。

  • ENDFILE{if (f && !g) print FILENAME; f=0;g=0}

    在每个文件的末尾,如果f为 true,g不是,则打印文件名。 然后,将f设置为g,两者恢复为零。

其他awk

对于缺少nextfileENDFILE功能的尴尬:

find . -type f -name '*.ext' -execdir awk '/brandedTerm/{f=1} /exclude1/ || /exclude2/{g=1; nextfile} END{if (f && !g) print FILENAME}' {} ;

逐行测试

要在包含brandedTerm但不包含exclude1exclude2的文件中显示每一行,请尝试:

find . -type f -name '*.ext' -exec awk '/brandedTerm/ && (!/exclude1|exclude2/) {if (!f)print "File "FILENAME; f=1; print}' {} ;

例如,请考虑以下三个感兴趣的文件:

$ cat dir/good1.ext
brandedTerm
exclude1 exclude2
$ cat dir/good2.ext
brandedTerm 1
exclude1 exclude2
brandedTerm 2
brandedTerm 3
$ cat dir/bad1.ext
brandedTerm exclude2
other line

如果我们运行我们的命令,我们会发现:

$ find . -type f -name '*.ext' -exec awk '/brandedTerm/ && (!/exclude1|exclude2/) {if (!f)print "File "FILENAME; f=1; print}' {} ;
File ./dir/good2.ext
brandedTerm 1
brandedTerm 2
brandedTerm 3
File ./dir/good1.ext
brandedTerm

我们的朋友发现允许链接多个 -exec 语句。

find . -type f -name "*.{extension}" 
-exec grep -q "{brandedTerm}" {} ";" 
-exec egrep -v "excl_1|excl_2|excl_3" {} ";"

请注意第一个 grep 中的 q,以将其设置为安静,以及 egrep,它允许添加多个模式以排除 (-v) |(或)。

最新更新