【问题标题】:Grep: How to exclude lines before/after if a line contains an unwanted string?Grep:如果一行包含不需要的字符串,如何排除之前/之后的行?
【发布时间】:2016-08-17 17:06:49
【问题描述】:

我在 2 个非常大的程序集转储上运行带有 diff 的命令。我看到很多这样的输出:

903c903
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
995c995
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
1123c1123
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
1191c1191
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
1278c1278
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
1347c1347
< ; Emitting BLENDED_CODE for generic X86 CPU
---
> ; Emitting BLENDED_CODE for Pentium 4
1546c1546
<        inc      dword ptr [ebp-10H]
---
>        add      dword ptr [ebp-10H], 1
1552c1552
<        inc      esi
---
>        add      esi, 1

我真的不想看到包含“Pentium 4”或“generic X86 CPU”的行;具体来说,如果有一行包含“Pentium 4”,我想排除该行及其上方的 3 行。

是否可以使用grep 做到这一点?我知道grep -v 'Pentium 4',但这仅适用于单行。 grep -v -- '---' 显然我做不到,因为有一些包含三连字符的有效差异。

如果在上面的代码上运行了 grep 查询,结果应该是

1546c1546
<        inc      dword ptr [ebp-10H]
---
>        add      dword ptr [ebp-10H], 1
1552c1552
<        inc      esi
---
>        add      esi, 1

【问题讨论】:

    标签: linux bash shell unix grep


    【解决方案1】:

    我喜欢这里的进程替换。假设 file_a 是:

    ; Emitting BLENDED_CODE for generic X86 CPU                                                                                                                                                          
    inc      dword ptr [ebp-10H]
    

    file_b 是:

    ; Emitting BLENDED_CODE for Pentium 4
    add      dword ptr [ebp-10H], 1
    

    跑步

    diff -I "^;" file_a file_b
    

    将返回:

    1,2c1,2
    < ; Emitting BLENDED_CODE for generic X86 CPU
    < inc      dword ptr [ebp-10H]
    ---
    > ; Emitting BLENDED_CODE for Pentium 4
    > add      dword ptr [ebp-10H], 1
    

    我猜这不是你想要的。但是,当您尝试使用进程替换时,即

    diff <(grep -v '^;' file_a) <(grep -v '^;' file_b)
    

    你会得到:

    1c1
    < inc      dword ptr [ebp-10H]
    ---
    > add      dword ptr [ebp-10H], 1
    

    【讨论】:

      【解决方案2】:

      您可以使用diff-I 选项从差异中排除匹配特定模式的行:

      diff -I 'Pentium 4\|generic X86 CPU' file1 file2
      

      模式必须由两行匹配,这就是为什么您需要使用|(逻辑)运算符来使模式匹配原始和更改。

      【讨论】:

        【解决方案3】:

        您可以使用bash 中的进程替换从源文件中去除 cmets:

        diff <(grep -v '^;' file1.s) <(grep -v '^;' file2.s)
        

        【讨论】:

        • 很好地发现这些线条实际上是 cmets!但我在这里看不到diff -I'^;' file1 file2 的优势。
        • @hek2mgl 没关系 - 在我完成打字之前,胖手指按了输入...我打算建议 diff -I'^;' ... 位,但我看到你打败了我......而且,是的,在在这种特殊情况下,diff -I 路由显然更有效,并且对于所述情况来说已经足够了。然而,可能存在更复杂的情况,指定忽略模式并不容易,因此我建议将进程替换配方作为替代工具......
        • :) 我了解到diff &lt;(cmd1) &lt;(cmd2) 的那一天改变了我的生活! (真的)
        【解决方案4】:
        $ awk '{r=r $0 ORS} (NR%4)==0{if (!/Pentium 4/) printf "%s", r; r=""}' file
        1546c1546
        <        inc      dword ptr [ebp-10H]
        ---
        >        add      dword ptr [ebp-10H], 1
        1552c1552
        <        inc      esi
        ---
        >        add      esi, 1
        

        【讨论】:

        • 此答案已被标记为低质量。如果它回答了问题,请考虑添加一些文字来解释它是如何工作的。
        • 不,这完全没有必要。您应该review 标记的答案而不是橡皮图章标记它的工具。请勿回复此内容,以免浪费我们的时间。
        • 即使答案在技术上是正确的,添加一些解释也很好,你不觉得 Ed 吗?
        • 绝对不是。如果用户不理解这一点,那么他们也不理解更多的绝对基本的 awk 语法/用法,所以他们最好在手册页中查找它,或者,上帝保佑,一本书比被勺子喂食的只是这一个独立的应用程序,然后他们会尝试将其应用于完全不合适的问题,因为这是他们所知道的一切。我真的不想再进入这个讨论了。
        猜你喜欢
        • 2021-04-07
        • 1970-01-01
        • 2012-10-18
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-07
        • 1970-01-01
        相关资源
        最近更新 更多