Is there any way to delete every m-th and n-th line of a sequence of every K
lines from a file using sed
or awk
?
Example:
cat input.txt
Aline1
Aline2
Aline3
Aline4
Aline5
Aline6
Aline7
Aline8
Aline9
Bline1
Bline2
Bline3
Bline4
Bline5
Bline6
Bline7
Bline8
Bline9
...
I want to remove every 3rd (line3) & 7th (line7) lines of a sequence of every 9 lines of the file. So the output will look like
Aline1
Aline2
Aline4
Aline5
Aline6
Aline8
Aline9
Bline1
Bline2
Bline4
Bline5
Bline6
Bline8
Bline9
...
I tried to combine two conditions at the same time but not successful:
awk '(NR)%3 && (NR)%7' input.txt
Edit:
Here 3rd and 7th lines refer to the lines in each of these sequences (Aline*
,Bline*
...) which consist of 9 lines each.
So the first 9lines of the input file define sequence-A in which I want to remove the 3rd and 7th lines.
The next 9 lines of the input file define sequence B and there I want to do the same. So this would correspond to the 12th and 16th lines of the original file.
PS. I do not want to find by characters*line3
& *line7
and delete them since in general, these lines might contain anything.
CodePudding user response:
Using GNU sed
$ sed '3~9d;7~9d' input_file
Aline1
Aline2
Aline4
Aline5
Aline6
Aline8
Aline9
Bline1
Bline2
Bline4
Bline5
Bline6
Bline8
Bline9
CodePudding user response:
Using any awk:
$ awk '(NR%9) !~ /^[37]$/' file
Aline1
Aline2
Aline4
Aline5
Aline6
Aline8
Aline9
Bline1
Bline2
Bline4
Bline5
Bline6
Bline8
Bline9
CodePudding user response:
A few awk
ideas:
awk -v line1=3 -v line2=7 -v inc=9 ' # line1/line2 are line numbers to ignore; inc(rement) is added to line1/line2 for next set of lines to ignore
FNR==line1 { line1 =inc; next } # skip line1, add "inc" for next line number
FNR==line2 { line2 =inc; next } # skip line2, add "inc" for next line number
1' input.txt # print current line
# or
awk -v line1=3 -v line2=7 -v blk=9 '
(FNR % blk == line1) || (FNR % blk == line2) {next}
1' input.txt
# or
awk -v line1=3 -v line2=7 -v blk=9 '
(FNR % blk != line1) && (FNR % blk != line2)
' input.txt
# or
awk -v line1=3 -v line2=7 -v blk=9 '
BEGIN { lines[line1]; lines[line2] }
! ((FNR % blk) in lines)
' input.txt
All generate:
Aline1
Aline2
Aline4
Aline5
Aline6
Aline8
Aline9
Bline1
Bline2
Bline4
Bline5
Bline6
Bline8
Bline9
CodePudding user response:
use this combo modulo ( ( NR % 9 ) % 4 ) < 3
::
mawk 'BEGIN { for(__=length(___="CBA"); __; __--) {
for(_^=___; _!~!_; _ ) {
print substr(___,__,!!_)_ } } }' |
{m,g}awk '($3 = ($2 = NR % 9 ) % 4 ) < 3'
A1 1 1
A2 2 2
A4 4 0
A5 5 1
A6 6 2
A8 8 0
A9 0 0
B1 1 1
B2 2 2
B4 4 0
B5 5 1
B6 6 2
B8 8 0
B9 0 0
C1 1 1
C2 2 2
C4 4 0
C5 5 1
C6 6 2
C8 8 0
C9 0 0
or better yet, simplify that to just either one of these :
( ( NR % 9 ) 1 ) % 4
( ( NR 1 ) % 9 ) % 4
most compact forms would be ::
awk '(NR%9 1)%4'
awk '(NR 1)%9%4' # valid but not recommended
CodePudding user response:
First, you need to extend your example with Aline10
line if you want to see the results you displayed otherwise Bline1
will be the 10th and not the 11th line as it is intuitive. So I created a file with Aline1
up to Aline20
.
With sed
you can easily remove the nth line with this syntax
$ cat test.txt | sed '1~3d'
Aline2
Aline3
Aline5
Aline6
Aline8
...
But you cannot pipeline two seds as the original line numbers will be modified so this is wrong:
$ cat test.txt | sed '1~3d' | sed '1~7d'
Aline3
Aline5
Aline6
Aline8
Aline9
Aline11
Aline14
Aline15
Aline17
Aline18
However this is a piece of cake with awk
$ cat test.txt | awk '{ if (NR%3!=0&&NR%7!=0) printf "%s\n",$0 }'
Aline1
Aline2
Aline4
Aline5
Aline8
Aline10
Aline11
Aline13
Aline16
Aline17
Aline19
CodePudding user response:
This might work for you (GNU sed):
sed -E 'x;s/^/x/;/^x{9}$/{s///;x;b};/^x{3}$|^x{7}$/{x;d};x' file
For each line in the file, swap to the hold space and insert an x
at the start of the line.
If the line contains 9 x
's, reset the hold space, swap back to the pattern space and break out of any further processing i.e. print that line.
If the line contains 3 or 7 x
's, swap back to the pattern space and delete that line.
For all other line swap back to the pattern space and print the line as normal.
Of course this can more easily be done using GNU sed specific commands:
sed '3~9d,7~9d' file