不要将连续匹配的上下文与grep合并

时间:2011-05-28 18:45:51

标签: grep matching

如果我在以下文件上运行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 ....

来做到这一点

4 个答案:

答案 0 :(得分:3)

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

你曾经使用过Python吗?在我看来,它是完成这类任务的完美语言(这段代码片段适用于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

答案 1 :(得分:2)

我不认为使用普通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

答案 2 :(得分:1)

我建议修补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的线性,整个补丁可能并不那么容易。然而,如果你有一个很好的补丁案例,它可能是值得的。

答案 3 :(得分:0)

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&amp;工具而不是高级解释器来获得所需的输出。

意见:所有优秀的操作系统都有:grep,awk,sed,tr,cut,head,tail,more,less,vi as built-ins。在最好的操作系统上,它们位于/ bin。