How to use 'sed or gawk' to delete a text block until the third line previous the last one

StackOverflow https://stackoverflow.com/questions/19203582

  •  30-06-2022
  •  | 
  •  

Frage

Good day, I was wondering how to delete a text block like this:

1    
2    
3    
4    
5    
6    
7    
8

and delete from the second line until the third line previous the last one, to obtain:

1    
2    
6    
7    
8

Thanks in advance!!!

BTW This text block is just an example, the real text blocks I working on are huge and each one differs among them in the line numbers.

War es hilfreich?

Lösung

Getting the number of lines with wc and using awk to print the requested range:

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

This allows you to easily change the range by just changing the value of M.

Andere Tipps

This might work for you (GNU sed):

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

or i f you prefer:

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

These always print the first two lines, then build a running window of three lines. Unless the end of file is reached the first line is popped off the window and deleted. At the end of file the remaining 3 lines are printed.

since you mentioned huge and also line numbers could be differ. I would suggest this awk one-liner:

awk 'NR<3{print;next}{delete a[NR-3];a[NR]=$0}END{for(x=NR-2;x<=NR;x++)print a[x]}' file
  • it processes the input file only once, without (pre) calculating total line numbers
  • it stores minimal data in memory, in all processing time, only 3 lines data were stored.
  • If you want to change the filtering criteria, for example, removing from line x to $-y, you just simply change the offset in the oneliner.

add a test:

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

Using :

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

It yields:

1
2
6
7
8
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top