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

时间:2018-01-20 06:38:05

标签: regex bash sed grep find

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

  1. 文件名
  2. 匹配模式的内容
  3. ...在我通过单行排除子模式消除大多数匹配(catch)的情况下。

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

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

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

    问题是这些匹配大部分都是我不关心的子模式,因为它们是注释或枚举名称等。我正在努力追捕的是在字符串中使用{brandedTerm}来修改/混淆研究的少量用例。

    我几乎可以达到我想要的水平: 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.)中找到这些后排除匹配项的文件;我希望编辑这些比赛的必要性。

    我摆弄的大多数途径(循环匹配文件和连接文件名/匹配然后排除 OR 重新搜索匹配模式w /排除应用)经证明是繁重而缓慢的。

    我认为有一些更简单的方法来查找文件&在以下情况下打印其匹配内容w / exclusions:

    1. 排除代表大部分匹配
    2. 适用多种排除模式。
    3. 思想?

      (另外,如果有重复请告诉我......在这个具体情况下无法找到任何内容,但是awk / sed是很好的,所以我很谨慎我没有找到正确的搜索短语来找到一些预先存在的答案。)

2 个答案:

答案 0 :(得分:1)

使用GNU awk,这将查找当前目录中包含正则表达式ext但不包含brandedTermexclude1的扩展名exclude2的所有文件:

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为真且g不是,则打印文件名。然后,将fg都设置为零。

其他awk

对于缺少nextfileENDFILE功能的awks:

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

答案 1 :(得分:0)

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

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

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