上一场比赛后如何打印第6至10行?

时间:2019-07-15 15:14:01

标签: awk sed grep

匹配最后一个“ Constrained”后,我想打印第6至第10行:

这是我尝试过的:

awk '/Constrained/ { print ; for(n=6; n<10; n++) { getline ; print } }' filename

但是不起作用。 我当时正在考虑使用tail -5仅获得最后5行。 (只有最后一场比赛的6至10)

您可以对此进行测试:

************************** Constrained Symmetrised Forces **************************
 *                                                                                  *
 *                           Cartesian components (eV/A)                            *
 * -------------------------------------------------------------------------------- *
 *                         x                    y                    z              *
 *                                                                                  *
 * O               1     -0.03440             -0.03440              0.00000         *
 * O               2      0.03440              0.03440             -0.00000         *
 * O               3     -0.03440              0.03440             -0.00000         *
 * O               4      0.03440             -0.03440              0.00000         *
 * Ti              1      0.00000              0.00000              0.00000         *

我应该得到以O开头和以Ti结尾的行。但是整个文件中都有几个“受限”

6 个答案:

答案 0 :(得分:3)

您需要的是:

grep -A10 Constrained file | tail -n 5

答案 1 :(得分:2)

一个选项:反转文件,找到第一个匹配项加上10行,然后反转,最后5行:

tac filename | grep -B10 Constrained -m 1 | tac | tail -n 5

答案 2 :(得分:2)

tac file | grep "Constrained" -m1 -B10 | tac | tail -n5

tac会反转文件,因此您可以使用grep -m1轻松找到最后一个匹配项。其次,您要先处理10行(跳过5行,打印5行)(“之前”,因为输出是相反的)。第二个tac再次反转输出,因此您将获得原始的行顺序,而tail -n5隐藏了Constrained和匹配后要打印的6.行之间的行。

当然,您可以使用简单的grep来执行此操作,但这将读取并处理整个文件,并且速度可能会大大降低。 tac从文件末尾开始读取。

grep -A10 "Constrained" file | tail -n5

使用awk(还读取整个文件):

awk '/Constrained/{f=NR;b=""};NR>=f+6 && NR<=f+10{b=b ORS $0}END{print b}' file

搜索“约束”,将初始行号(f设置为当前行)并删除缓冲区(用于先前的结果)。然后,只要行号与该区域匹配,就将行收集到b中。

答案 3 :(得分:1)

我想到的最简单的方法是两次读取文件。第一次通过查找匹配的最后一行,第二次通过后显示6-10。

awk 'FNR==NR && /Constrained/ { line=NR }
     FNR!=NR && FNR >= line+6 && FNR <= line+10' filename filename

答案 4 :(得分:1)

一次读取文件,但要跟踪缓冲区:

awk '(c-->0){b[10-c]=$0}
     /Constrained/{c=10}
     END{for(i=6;i<=10;++i) print b[i] }' file

这是如何工作的?

数组b是缓冲区,在匹配模式/Constrained/之后总是包含10行。计数器c将用于递减计数至零。每次找到该模式的匹配项,都会将其重置为最大值10。该程序的工作方式如下:

  1. 读取一行(默认awk操作)
  2. 检查计数器c是否大于零并将其减小1(请参见What is the "-->" operator in C++?)。如果满足此条件,则将该行存储在缓冲区b中。因为我们从9(10-1)开始计数,所以将其存储在位置 10 − i 。这样,比赛之后的行将被索引为1,2,3,...,10。
  3. 如果匹配模式/Constrained/,则将计数器c重置为10。
  4. 除非您位于文件末尾,否则请返回1。
  5. 如果您处理了文件,则缓冲区b现在包含匹配后的最后10行。只需打印6至10行即可。

几次清理:

不一定要说在匹配模式之后,您有10行,因此必须确保完全擦除了先前的缓冲区。

$ awk '(c-->0){b[10-c]=$0}
       /Constrained/{c=10; delete b}
       END{for(i=6;i<=10;++i) if (i in b) print b[i] }' file

参数化版本:

参数化版本将允许较大范围。但是想象一下,您想要比赛后的10000至10001行。因此,缓冲区只有两行,实际上会很大。因此,我们可以将其更正为:

$ awk '(c-->min) && (c<=max-min){b[max-c]=$0}
       ($0~ere){c=max; delete b}
       END{for(i=min;i<=max;++i) if (i in b) print b[i] }' \
       min=6 max=10 ere="Constrained" file

请注意,min必须大于0。

原理证明:

$ awk '(c-->0) && (c<=max-min){b[max-c]=$0}
       ($0~ere){ c=max; delete b}
       END{for(i=min;i<=max;i++) if(i in b) print b[i] }' \
       min=6 max=10 ere="20" <( seq 1 50 && seq 101 150 )
126
127
128
129
130

答案 5 :(得分:0)

我建议尝试这个。 -A表示单词匹配后的10行。 -m表示何时停止读取文件。我们不想读取整个文件。你呢?

grep -A10 Constrained file | tail -5