Printing nth rows after a row number in awk

Viewed 72
    1,A
    2,B
    3,C
    4,D
    5,E
    6,F
    7,G
    8,H
    9,I
   10,J
   11,K
   12,L
   13,M
   14,N

How do I print row 4 first and then the 9th row and then the 14th row using awk? I want to first print the 4th row and then continue printing every 5th row after the 4th row, until the end of the file. I tried this:

awk '{if(NR==4 || (NR>4 && NR==NR+7)) print $0}' file

But this doesn't work. Any help is appreciated.

The output should be:

4,D
9,I
14,N
4 Answers

Assuming you want to print every 5th line starting from a specific line number:

$ seq 20 | awk 'NR==4{c=4} c && !((++c) % 5)'
4
9
14
19

$ seq 20 | awk 'NR==2{c=4} c && !((++c) % 5)'
2
7
12
17

$ seq 20 | awk 'NR==6{c=4} c && !((++c) % 5)'
6
11
16

c && !((++c) % 5) says:

If c is set then increment c and test if that new value modulo 5 is zero.

So no line before NR==4 can be printed as c is never populated before that happens, and then when c is set to 4, it's then increment to 5 and 5 % 5 is 0 so the line is printed. c gets incremented for every line after that and so c % 5 continually rotates through 1 2 3 4 0 thus printing every 5th line when 0 occurs and so !0 is true.

To do the above using values set on the command line rather than hard-coded in the script would be:

$ seq 20 | awk -v b=4 -v n=5 'NR==b{c=n-1} c && !((++c) % n)'
4
9
14
19

EDIT - here's why I asked:

is your question truly I want to firs print the 4th row and then continue printing every 5th row after the 4th row as you stated or is it the simpler I want to print the 4th row out of every 5 rows?

to which the OP replied

what I want to do is what I wrote exactly

and the difference between the possible solutions to THAT problem when you generalize to be able to change "4th" to some other number, e.g. "6th":

I want to firs print the 6th row and then continue printing every 5th row after the 6th row

$ seq 20 | awk 'NR==6{c=4} c && !((++c) % 5)'
6
11
16

$ seq 20 | awk 'NR%5==6'
$

Simply

awk 'NR%5 == 4' file

will do the job. Alternatively, if you have GNU sed:

sed -n 4~5p file

Edit:
A general solution to the problem of printing every nth line starting with line s using awk could be, for example, like that:

awk -v s=6 -v n=5 'NR>=s && NR%n == s%n' file

(s%n could be precomputed and assigned to a variable.)

But using GNU sed would be much simpler for this task:

sed -n "${s}~${n}p" file

where s and n are shell variables (their values must be positive integers).

Your code

awk '{if(NR==4 || (NR>4 && NR==NR+7)) print $0}' file

contain condition NR==NR+7 which does never hold, in turn what is right to || is always false and therefore your code is in fact acting like it would be

awk '{if(NR==4) print $0}' file

print row 4 first and then the 9th row and then the 14th row using awk?

Just provide GNU AWK with ;-sheared conditions describing lines you want that is

awk 'NR==4;NR==9;NR==14' file

Keep in mind that altering order does not change output, so you will get same output for

awk 'NR==14;NR==9;NR==4' file

(tested in GNU Awk 5.0.1)

  • doing it in awk without ever using modulo % :
jot 30 | mawk 'BEGIN { __+=_+=_+=__=_^=FS="^$" } _-(_+=__*(_==NR))'
4
9
14
19
24
29
  • generic solution without modulo % :

    -- "1st print 17th row then once every 29 rows after that"

jot 200 | gawk '__-(__+=___*(NR == __))' FS='^$' __=17 ___=29
17
46
75
104
133
162
191
  • extremely succinct way if u only want odd-numbered rows :
jot 14 | nawk '_*=--_'
1
3
5
7
9
11
13
Related