我有一个看起来像的文件:
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
<empty line here>
Total DOS and NOS and partial (IT) DOSDOWN
<empty line here>
E Total 1
<empty line here>
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
-1.4859 0.004 0.000 0.004
-1.4812 0.004 0.000 0.004
0.3563 0.708 5.510 0.708
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149
<empty line here>
Sublattice 1 Atom Fe spin DOWN
我想要的是提取(第一个模式)
之间的所有行 Total DOS and NOS and partial (IT) DOSUP
<empty line here>
E Total 1
<empty line here>
和(第二种模式)
<empty line here>
Sublattice 1 Atom Fe spin DOWN
即。我想得到
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
-1.4859 0.004 0.000 0.004
-1.4812 0.004 0.000 0.004
0.3563 0.708 5.510 0.708
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149
所以,在一天结束时,我想在两个多线模式之间划线。
据我所知,awk
可以通过状态机检测多行模式(请参阅here),但在我的情况下我没有这样做。
非常感谢任何有关如何解决此问题的建议。
答案 0 :(得分:2)
这是基于Ed Morton诀窍的解决方案。
awk -v RS= 'n==2; /Total DOS/ || n {n++;next} {n=0}' input.txt
这是如何运作的。
RS=
将awk置于多行模式,以便记录包含行块。n==2;
打印满足此条件时处理的所有记录。/RE/ || n
是一个条件,如果RE(模式)在当前记录中匹配或变量n
非零,则计算结果为真。{n++;next}
显然会增加n
并跳到下一条记录。{n=0}
如果我们尚未跳到下一条记录,我们会重置n
。所有这一切的效果是我们打印的记录是具有匹配模式的记录之后的两个记录。当然,您可以根据自己的喜好调整开始计数器的条件。例如$2=="Total"
。盐味。
sh-3.2$ cat input.txt
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
Total DOS and NOS and partial (IT) DOSUP
E Total 1
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
....... ..... ..... .....
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149
blah blah blah blah
sh-3.2$ awk -v RS= 'n==2; /Total DOS and NOS/||n{n++;next} {n=0}' input.txt
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
....... ..... ..... .....
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149
答案 1 :(得分:1)
使用sed
:sed -n '5,/^$/{/^$/d}'
但是假设“多行起始模式”始终位于文件的开头。否则会变得有点复杂。像这样:
/Total/{N;N;N}
/Total.*Total/,/^$/{
/Total/d
/^$/d
}
这里我假设'Total'匹配多线模式的开头,'Total。* Total'匹配整个模式。如果有其他模式以多行模式的第一行开头但短于4行,则将N;N;N
替换为更复杂的内容。
答案 2 :(得分:1)
从您的评论中,您所需要的只是:
awk -v RS= '/Total DOS/{tgt=NR+2} NR==tgt' file
如果没有,请编辑您的问题以澄清。如果您只想要文件输出中的第一个匹配块并且效率是一个问题,请将其设为NR==tgt{print; exit}
。如有必要,请将正则表达式更改为您需要匹配的Total DOS...
行,以使其唯一。
这是针对您提供的示例输入运行的:
$ cat file
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah
Total DOS and NOS and partial (IT) DOSUP
E Total 1
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
....... ..... ..... .....
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149
blah blah blah blah
$ awk -v RS= '/Total DOS/{tgt=NR+2} NR==tgt' file
-1.5000 0.004 0.000 0.004
-1.4953 0.004 0.000 0.004
-1.4906 0.004 0.000 0.004
....... ..... ..... .....
0.3609 0.562 5.513 0.562
0.3656 0.381 5.515 0.381
0.3703 0.149 5.517 0.149