infile中:
[start] cmd1
afadfadf
dafdf
[ok] cmd1
[-] cmd2
[-] cmd3
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[-] cmd5
[-] cmd6
[start] cmd1
adfadd
dafa
dfdd33r55ae
[ok] cmd1
[-] cmd7
[start] cmd8
error...
[stop] cmd8
[-] cmd9
[start] cmd10
exit xx
[stop] cmd10
[-] cmd
[start] cmd1
[ok] cmd1
我想打印所有块,如:[start] ... [stop] cmd ...
结果应为:
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[start] cmd8
error...
[stop] cmd8
[start] cmd10
exit xx
[stop] cmd10
我怎么能用sed做到这一点?
sed -n '/\[start\]/I,/\[stop\]/I p'
无效,因为范围运算符在找到下一个[停止]之前不会停止。
编辑: 使用@jaybee sed脚本后,我发现当[停止]行多于起始行 时,它仍然有一些问题, ,例如:
infile2
[start] cmd1
afadfadf
dafdf
[ok] cmd1
[-] cmd2
[-] cmd3
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[-] cmd5
[-] cmd6
[start] cmd1
adfadd
dafa
dfdd33r55ae
[ok] cmd1
[-] cmd7
[start] cmd8
error...
[stop] cmd8
[-] cmd9
[stop] sum
[stop] cmd1
[stop] cmd2
[start] cmd10
exit xx
[stop] cmd10
[-] cmd
[start] cmd1
[ok] cmd1
它仍会输出额外的[stop]行,如下所示:
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[start] cmd8
error...
[stop] cmd8
[stop] cmd8
[-] cmd9
[stop] sum
[stop] sum
[stop] cmd1
[stop] cmd2
[stop] cmd2
[start] cmd10
exit xx
[stop] cmd10
所以我决定修改sedsrc来解决这个问题:
#n
/^\[start\]/I {h;d}
#if match [start] create a new hold buffer then delete the pattern space
/^\[stop\]/I {
#if match [stop] do this
H;x
#append line into hold buffer and then swap the hold buffer to pattern space
/^\[start\]/I{p;d}
#if the buffer contain [start], then it is a complete [start]...[stop] block, print the block,start over with next line
d
#if does not contain [start],start over with next line
}
/^\[.+\]/ {
#if it is other control word, do this
h;d
# clear and put current line to hold buffer, start over with next line
}
H
#append non-control line into hold buffer
现在它运行正常,欢迎将来讨论如何使脚本更简洁。
答案 0 :(得分:5)
好的,所以我建议您使用保留缓冲区,每当看到新的[start]
时都将其刷新,并在看到[stop]
时打印它。这给出了以下脚本:
#n
/^\[start\]/I {
h;n
}
/^\[stop\]/I {
H;x;p;n
}
H
你把它放在例如sedscr
然后运行它以获得以下结果:
$ sed -f sedscr infile
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[start] cmd1
adfadd
dafa
dfdd33r55ae
[stop] cmd1
[start] cmd8
error...
[stop] cmd8
[start] cmd10
exit xx
[stop] cmd10
在行的开头看到[start]
(带有I
标志,因为您似乎想要不区分大小写),将该行放入保留空间,删除其先前的内容({ {1}})然后输入下一行(h
)。
当人们看到n
时,将该行附加到保留空间([stop]
),然后交换模式空间并保留空间(H
)以打印模式空间({{1然后输入下一行(x
)。
在所有其他行上,只需将该行附加到当前保留空间(p
)。
顺便说一句,我脚本开头的n
相当于命令行上的H
:请求 sed 不将模式空间输出到输出流,除非#n
命令询问。
答案 1 :(得分:3)
以下是应该有效的awk
:
awk '/^\[start\]/ {i=1;delete a} {a[i++]=$0} /^\[stop\]/ {for (j=1;j<i;j++) print a[j]}' file
[start] cmd4
dfdafadf
d
afasdf
daf
[stop] cmd4
[start] cmd1
adfadd
dafa
dfdd33r55ae
[stop] cmd1
[start] cmd8
error...
[stop] cmd8
[start] cmd10
exit xx
[stop] cmd10
如果start
具有end
,则仅从start
打印
每次看到stop
时,它都会重置数组并开始向其存储数据
如果找到{{1}},则打印出阵列。
答案 2 :(得分:0)
这可能适合你(GNU sed):
sed ':a;/^\[start\|stop\]/I{:b;$!{n;/^\[/ba;bb}};d' file
如果该行开始[start]
或[stop]
(大写或小写),请将其打印以及不会开始[
的所有后续行。如果下一行以[
循环开头并重新开始检查,则删除它。
编辑:
另一个答案可能是:
sed '/^\[start\]/I{h;d};H;/^\[stop\]/I{x;p;x};d' file
编辑:
根据正在修改的问题:
sed '/^\[start\]/I{:a;x;/^\(.*\[stop\][^\n]*\).*/Is//\1/p;x;h;d};H;$ba;d' file