如何使用'sed或gawk'删除文本块,直到最后一行之前的第三行

时间:2013-10-05 22:57:47

标签: sed gawk

美好的一天, 我想知道如何删除这样的文本块:

1    
2    
3    
4    
5    
6    
7    
8

并从第二行删除,直到最后一行之前的第三行,以获得:

1    
2    
6    
7    
8

提前致谢!!!

BTW 这个文本块只是一个例子,我正在处理的真实文本块很大,每个都在行号中有所区别。

4 个答案:

答案 0 :(得分:3)

使用wc获取行数并使用awk打印请求的范围:

$ awk 'NR<M || NR>N-M' M=3 N="$(wc -l file)" file
1
2
6
7
8

这使您只需更改M的值即可轻松更改范围。

答案 1 :(得分:3)

这可能适合你(GNU sed):

sed '3,${:a;$!{N;s/\n/&/3;Ta;D}}' file

或者您更喜欢:

sed '1,2b;:a;$!{N;s/\n/&/3;Ta;D}' file

这些总是打印前两行,然后构建一个三行的运行窗口。 除非到达文件末尾,否则第一行将从窗口弹出并删除。在文件末尾打印剩余的3行。

答案 2 :(得分:2)

因为您提到巨大,行号可能不同。我会建议这个awk单行:

awk 'NR<3{print;next}{delete a[NR-3];a[NR]=$0}END{for(x=NR-2;x<=NR;x++)print a[x]}' file
  • 它只处理输入文件一次,没有(预先)计算总行数
  • 它将最少的数据存储在内存中,在所有处理时间内,只存储了3行数据。
  • 如果您想更改过滤条件,例如,从第x行移至$-y,您只需更改oneliner中的偏移量。

添加测试:

kent$  seq 8|awk 'NR<3{print;next}{delete a[NR-3];a[NR]=$0}END{for(x=NR-2;x<=NR;x++)print a[x]}'
1
2
6
7
8

答案 3 :(得分:1)

使用

sed -n '
    ## Append second line, print first two lines and delete them.
    N; 
    p; 
    s/^.*$//;
    ## Read next three lines removing leading newline character inserted
    ## by the "N" command.
    N; 
    s/^\n//; 
    N; 
    :a; 
    N;
    ## I will keep three lines in buffer until last line when I will print
    ## them and exit.
    $ { p; q };
    ## Not last line yet, so remove one line of buffer based in FIFO algorithm.
    s/^[^\n]*\n//; 
    ## Goto label "a".
    ba
' infile

它产生:

1
2
6
7
8