【问题标题】:Do not merge the context of contiguous matches with grep不要将连续匹配的上下文与 grep 合并
【发布时间】:2011-09-04 01:22:45
【问题描述】:

如果我对以下文件运行 grep -C 1 match

a
b
match1
c
d
e
match2
f
match3
g

我得到以下输出:

b
match1
c
--
e
match2
f
match3
g

如您所见,由于连续匹配“match2”和“match3”周围的上下文重叠,因此它们被合并了。但是,我更愿意为每个匹配获取一个上下文描述,可能会从上下文报告中的输入复制行。在这种情况下,我想要的是:

b
match1
c
--
e
match2
f
--
f
match3
g

实现这一目标的最佳方法是什么?我更喜欢通用性足以适应其他grep 选项的解决方案(-A-B-C 的不同值或完全不同的标志)。理想情况下,我希望有一个聪明的方法来做到这一点,只需 grep....

【问题讨论】:

    标签: grep matching


    【解决方案1】:

    我认为使用普通的 grep 是不可能做到这一点的。

    下面的 sed 结构在一定程度上起作用了,现在我只需要弄清楚如何添加“--”分隔符

    $ sed -n -e '/match/{x;1!p;g;$!N;p;D;}' -e h log
    b
    match1
    c
    e
    match2
    f
    f
    match3
    g
    

    【讨论】:

    • 这是他已经得到的输出;他想要别的东西。请在回答之前阅读问题。
    • 这并不完美,因为如果您想拥有不同的 -C 或 -A 或 -B 值,则必须以不明显的方式更改 sed 表达式......提及使用其他grep 选项。
    • @a3_nm 这是解决方案的合理要求,但它没有出现在原始问题中。我建议你编辑你的问题添加它。
    • 您真正需要的只是输出的装饰器。您知道要搜索的标记 - 这足以复制重复标记的行,插入 --。我认为这个sed 解决方案会让您朝着正确的方向前进。你可以编写一个 shell 脚本,用他的想法简单地调用 grep,传递任意参数并完成你的问题。
    【解决方案2】:

    我认为使用普通的 grep 是不可能的。

    你用过 Python 吗?在我看来,它是完成此类任务的完美语言(此代码 sn-p 适用于 Python 2.7 和 3.x):

    with open("your_file_name") as f:
       lines = [line.rstrip() for line in f.readlines()]
       for num, line in enumerate(lines):
          if "match" in line:
             if num > 0:
                print(lines[num - 1])
    
             print(line)
    
             if num < len(lines) - 1:
                print(lines[num + 1])
                if num < len(lines) - 2:
                   print("--")
    

    这给了我:

    b
    match1
    c
    --
    e
    match2
    f
    --
    f
    match3
    g
    

    【讨论】:

    • 这需要适应grep 的更精细用途。仅仅因为缺少这个选项,就不得不以一种简单的方式重新实现匹配(grep 以一种非常聪明的方式做到了),这种感觉并不令人满意。无论如何,谢谢你的建议!
    【解决方案3】:

    我建议修补 grep 而不是解决它。在 src/main.cpp 中的 GNU grep 2.9 中:

    933       /* We print the SEP_STR_GROUP separator only if our output is
    934          discontiguous from the last output in the file. */
    935       if ((out_before || out_after) && used && p != lastout && group_separator)
    936         {
    937           PR_SGR_START_IF(sep_color);
    938           fputs (group_separator, stdout);
    939           PR_SGR_END_IF(sep_color);
    940           fputc('\n', stdout);
    941         }
    942 
    

    一个简单的附加标志就足够了。

    编辑:嗯,哦,这当然不是那么简单,因为 grep 不会重现上下文,只需添加更多分隔符。由于 grep 的线性,整个补丁可能并不那么容易。不过,如果你有一个很好的补丁案例,它可能是值得的。

    【讨论】:

      【解决方案4】:

      这对于 grep 或 GNU grep 似乎是不可能的。但是,可以使用标准 POSIX 工具和像 bash 这样的良好 shell 作为杠杆来获得所需的输出。
      注意:解决方案不需要 python 和 perl。最坏的情况,使用 awk 或 sed。

      我快速原型化的一个解决方案是这样的(它确实涉及重新读取文件的开销,这个解决方案取决于这个开销是否可以,并且赠品是原始问题对 -1 的固定使用允许简单使用头部和尾部的上下文行数):

      $ OIFS="$IFS"; lines=`grep -n match greptext.txt | /bin/cut -f1 -d:`; 
      for l in $lines; 
      do IFS=""; match=`/bin/tail -n +$(($l-1)) greptext.txt | /bin/head -3`; 
      echo $match; echo "---"; 
      done; IFS="$OIFS"
      

      这可能有一些与它相关的极端情况,这可能会在不需要时重置 IFS,尽管它是尝试使用 POSIX shell 和工具的强大功能而不是高级解释器来获得所需输出的提示。

      意见:所有好的操作系统都内置了:grep、awk、sed、tr、cut、head、tail、more、less、vi。在最好的操作系统上,这些都在 /bin 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-28
        • 1970-01-01
        • 2020-10-15
        • 1970-01-01
        • 1970-01-01
        • 2012-08-31
        • 1970-01-01
        相关资源
        最近更新 更多