我有一个文件,其中包含以下格式的条目:
2012-01-12 22:20:21,638 INFO [Tracer]
something.of.interest
...some number of additional lines...
<<a blank line>>
...other stuff...
我只想挑出第一行包含[Tracer]的文本块,第二行包含 something.of.interest ,以空白行结尾,后面有未知行数第二行。无法更改文件格式。
我可以通过做类似的事情来使用sed来挑选整个块:
gsed -n '/^[0-9]\{4\}[^\[]*\[Tracer\]/,/^$/ p' /path/to/file/to/parse
这会按预期选择整个块,但它匹配第二行不包含something.of.interest的条目。
我可以使用N来获取下一行,然后在当前行和下一行之间进行匹配,只有当我看到[Tracer]和something.of.interest由\分隔时,我才能选择前两行。 ñ但是我似乎无法弄清楚如何抓住以下几行直到我换到换行符。在伪sed我想做这样的事情:
/look for Tracer line 1/{
N
/look for \n.*something.of.interest/
},
/look for blank line for end of range/
p
可悲的是,这实际上并不起作用,通常我会得到并且“未知命令”&#39;信息。
有没有办法在sed中使用模式定义范围,其中开头和结尾可能是多行模式?
解决方案最终需要在Solaris 5.10上运行。 GNU sed(gsed)是可用的,如果在这种情况下这是一个更好的选择,那就是awk。
建议非常感谢。
更新
似乎我可以用awk来做,虽然结果有点可怕。我非常喜欢更优雅的解决方案,这里仍然可以参考awk脚本找到感兴趣的行:
1)创建一个文件something.awk,其中第一行是与第1行匹配的正则表达式:
/\[Tracer\]/ {
l1=$0
if (getline <= 0) {
print "getline failed"
exit 1
}
if (index($0, L2MARKER) > 0) {
print l1
print $0
stop=0
while(stop != 1) {
if (getline <= 0) {
print "getline failed :( ERRNO:" + ERRNO
exit 1
}
print;
if (length($0) == 0) {
stop = 1
}
}
}
}
2)从shell调用,类似于 awk -f something.awk L2MARKER =&#39; something.of.interest&#39; the.file.to.parse
答案 0 :(得分:2)
编辑:有人注意到我的第一个解决方案有点偏差。这是一个尝试修复,虽然我还没有测试它,因为没有测试它的地方。
我在sed
:
/Tracer/ { N; /interesting/ { h; :a; n; H; /^$/! ba; g; p } }
接下来是解释!
给出这样的测试文件:
boring
boring
awesome [Tracer]
interesting
totally interesting
and awesome
still interesting
very interesting
back to boring
awesome [Tracer]
Nah just kidding
nope
darn
以上命令扩展为以下内容,并附有说明:
/Tracer/ { # Looks for Tracer
N # Moves on to the next line
/interesting/ { # Looks to see if "interesting" is in the next line
h # Put first two lines in hold space
:a # Label "a"
n # Move on to next line
H # Appends line to hold space
/^$/! ba # If not a blank line, branch back to "a"
g # Put the hold space into the pattern space
p # Print the pattern space
}
}
而且,应该这样做:
sed -n '/Tracer/ { h; n; /interesting/ { :a; H; n; /^$/! ba }; g; p }' file.txt
awesome [Tracer]
interesting
totally interesting
and awesome
still interesting
very interesting
[blank line]
[blank line]
是一个文字空行,但我不能在这里的代码块中表达。显然,您可以轻松地修改/Tracer/
和/interesting/
的正则表达式,具体取决于行的具体内容。
答案 1 :(得分:0)
另一个awk解决方案
如果要提取的块总是在文件的顶部,并且输出中只有1或0块:
awk '/\[Tracer\]/{print;f=1;next;}
{if(NR==2){if(f && $0~/interest/){print;next;} else exit;}
if(f && $0) print; else exit;}' file
如果你想要捕获更多的块:
awk '/\[Tracer\]/{h=$0;f=1;l=NR;next;}
{if(NR==l+1){if(f && $0~/interest/){print h;print;} else {f=0;h=""; }next;}
if(f) if($0)print;else f=0; }' file
测试上述
#input file, in this case, 1st and 3rd blocks should be
in your output (for solution 2)
kent$ cat file
2012-01-12 22:20:21,638 INFO [Tracer]
interesting
...some number of additional lines...
xxx
yyy
zzz
...other stuff...
2012-01-12 22:20:21,638 INFO [Tracer]
NOT-wanted-NOT
...some number of additional lines...
xxx####
yyy####
zzz####
...other #### stuff...
2012-01-12 22:20:21,638 INFO [Tracer]
interest
...some number of additional lines...
xxxWANTWANTWANT
yyy.WANTWANTWANT
zzzoWANTWANTWANT
blahblah
#solution one:
kent$ awk '/\[Tracer\]/{print;f=1;next;}
{if(NR==2){if(f && $0~/interest/){print;next;} else exit;}
if(f && $0) print; else exit;}' file
2012-01-12 22:20:21,638 INFO [Tracer]
interesting
...some number of additional lines...
xxx
yyy
zzz
#solution two:
kent$ awk '/\[Tracer\]/{h=$0;f=1;l=NR;next;}
{if(NR==l+1){if(f && $0~/interest/){print h;print;} else {f=0;h=""; }next;}
if(f) if($0)print;else f=0; }' file
2012-01-12 22:20:21,638 INFO [Tracer]
interesting
...some number of additional lines...
xxx
yyy
zzz
2012-01-12 22:20:21,638 INFO [Tracer]
interest
...some number of additional lines...
xxxWANTWANTWANT
yyy.WANTWANTWANT
zzzoWANTWANTWANT
希望它有所帮助。
答案 2 :(得分:0)
这是另一个awk
解决方案:
awk '/\[Tracer\]/{
a=$0;getline;
if ($0~/something\.of\.interest/) {print a; print$0;getline} else next;
while ($0!~/^$/) {print $0;getline}}' INPUT_FILE
答案 3 :(得分:0)
如果可以保证[Tracer]
行正上方有一个空行,
awk 'BEGIN { RS = ""; FS = "\n" } $1 ~ "[Tracer]" && $2 ~ "something.of.interest"' input.file
如果没有,请添加sed
以确保它:
sed 's/\(.*\[Tracer\].*\)/\n\1/' test.in |awk \
'BEGIN { RS=""; FS="\n" } $1 ~ "[Tracer]" && $2 ~ "something.of.interest"'
答案 4 :(得分:0)
Sed有一个专为此类应用设计的保留空间:
sed -n '/^[0-9]\{4\}[^\[]*\[Tracer\]/,/^$/H;/^$/{x;/interesting/p;s/.*//g;x;}'
答案 5 :(得分:0)
这可能对您有用:
sed -n '/Tracer/,/^$/{H;//{x;/something.of.interest/p}}' file
说明:
-n
禁止自动打印输出,即打印输出使用p
或P
命令。/Tracer/
和/^$
之间的一系列行。H
/Tracer/
或/^$/
中的任何一个匹配,请执行以下//
:
x
/something.of.interest/
,如果是,则打印出HS /.../p
PS始终首先在感兴趣的行之间附加到HS(H
)。 //
的第一个匹配将匹配第一个地址,即/Tracer/
此时HS变为PS,PS变为HS。没有匹配,因为/something.of.interest/
尚未被读入。因为没有匹配,所以没有打印出来但现在HS包含第一个地址,后续行被附加到它,直到第二个地址匹配。交换了PS和HS,这次/something.of.interest/
匹配,并打印出/Tracer/
和/^$/
之间的所有行。
答案 6 :(得分:0)
我找到Perl以“段落”模式阅读文字:
perl -00 -ne '
@lines = split /\n/;
print if $lines[0] =~ /Tracer/ and $lines[1] =~ /something.of.interest/
'