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