一直在这里搜索并且接近但似乎仍然不是我正在尝试做的事情。例如。请考虑以下样本测试输入,目标是找到跨越包含“abc”(打印此行)的行的多行的匹配,并以包含“efg”(也打印此行)的行结束,并且还在两者之间打印线条。
yyabc}
000
iiabc<
{efg+1}
111
yyabc}
222
p {efg+13}
zzz
z {efg+243} {}
iii
oooabc>
ooo
与我正在寻找的最接近的是,将zzz作为带有上述行的测试输入文件,
sed -e '/abc/,/efg/!d' zzz
,但包括额外的行,不介意不在那里,
yyabc} <<***** extra
000 <<***** extra
iiabc<
{efg+1}
yyabc}
222
p {efg+13}
oooabc> <<***** extra
ooo <<***** extra
,因此预期输出为,
iiabc<
{efg+1}
yyabc}
222
p {efg+13}
除了依赖pcregrep(我在linux框中还有其他所有东西)之外,还有一个可以产生这样多行匹配的解决方案吗?
非常感谢。
答案 0 :(得分:1)
sed -n '/abc/,/efg/ {
H
/efg/ {
g
:a
s/^.*\n\(.*abc\)/\1/
ta
p
}
}' zzz
使用缓冲区捕获abc和第一个efg之间的部分,而不是删除最后一个abc行之前的任何行,最后打印结果并继续文本的其余部分。
如果abc与efg位于同一行,并且之前没有来自&#34;相同的&#34;文本的一部分,因为sed //,//
从一行上的patterne工作到另一行上的模式
答案 1 :(得分:1)
awk
非常适合这项任务。如果测试输入文件名为zzz
,则运行:
$ awk '/abc/{a=""} /abc/,/efg/{a=a"\n"$0} /efg/{print substr(a,2);a=""}' zzz
iiabc<
{efg+1}
yyabc}
222
p {efg+13}
说明:
/abc/{a=""}
每次到达包含“abc”的行时,将变量a
设置为空字符串。 (我们要打印的行将在下一步中添加到此变量中。)
/abc/,/efg/{a=a"\n"$0}
在以包含abc
的行开头并以包含efg
的行结尾的每一行范围内,每行都会附加到变量a
。
/efg/{print substr(a,2);a=""}
当达到范围中的最后一行时,打印出a
。由于a
以额外的换行符开头,我们会使用substr
将其删除。
如果没有上面的第一步,程序运行正常,但会打印“额外”行。包括第一步,它们就被淘汰了。
答案 2 :(得分:1)
使用perl one-liner打包整个文件:
perl -0777 -ne 'print /.*abc.*\n(?:(?!.*(?:abc|efg)).*\n)*.*efg.*\n/g' file.txt
或逐行缓冲解决方案:
perl -ne '
$b = /abc/ ? $_ : "$b$_";
print $b if (/abc/ .. /efg/) =~ /E/
' file.txt
切换:
-0777
:覆盖整个文件。-n
:为输入文件中的每个“行”创建一个while(<>){...}
循环。 -e
:告诉perl
在命令行上执行代码。 答案 3 :(得分:1)
这可能适合你(GNU sed):
sed -n '/abc/,/efg/{/abc/{h;d};H;/efg/{g;p}}' file
通过调用-n
开关在“grep”模式下使用sed。过滤abc
和efg`之间感兴趣的行。使用保留空间(HS)存储包含线,然后将其打印出来。
替代:
sed -n '/abc/,/efg/{/abc/h;//!H;/efg/{x;p}}' file
答案 4 :(得分:0)
答案 5 :(得分:0)
基于阵列的直接awk解决方案:
awk '/abc/ {delete a;j=0;flag=1}
flag {a[++j]=$0}
/efg/ && flag {for (i=1;i<=j;i++){print a[i]};flag=0}' inputfile
/abc/ {delete a;j=0;flag=1}
:找到初始模式时,删除数组,将counter设置为零并打开&#34; find&#34;标志。
flag {a[++j]=$0}
:标记开启时存储行内容。
/efg/ && flag {for (i=1;i<=j;i++){print a[i]};flag=0}
:当找到结束模式并打开标志时,显示数组并关闭标志