Passing Variable to NR in AWK command not working

17,573

Solution 1

There are several problems with your script. The immediate problem is that in the second call to awk, you use single quotes around the script, so $line_start and $line_end are variables expanded by the shell, they're passed literally as part of the script to awk. You can fix this by using double quotes instead.

awk "NR==$line_start, NR==$line_end" file

This works only because $line_start and $line_end are numbers. If they were strings, you couldn't do this, because the values of the shell variables end up being parsed by awk as part of awk code, not as strings. In general, to pass a string to an awk script, you can use the idiom with -v to define awk variables with the same name as the shell variables (or with different names if you prefer):

awk -v "line_start=$line_start" -v "line_end=$line_end" 'NR==line_start, NR==line_end' file

There are more problems with your script.

  • You parse the file twice. This can be slow if the file is large, and it is impossible if the data comes from a pipe instead of a disk file.
  • If there is more than one match for /regex/, then $line_start will contain a list of line numbers. The shell will complain of a syntax error on the let line.

If you want to show 5 lines following a match, do the counting inside awk.

awk '
  /regex/ { show_lines = 5 }
  show_lines { print; --show_lines; }
' file

If you only want to show the first matching block, exit once show_lines reaches 0.

  show_lines { print; --show_lines; if (!show_lines) exit; }

Solution 2

You can use sed for this:

sed -n '/regex/{N;N;N;N;N;p}' file

Or change the awk solution:

line_start=$(awk '/regex/{print NR}' file) 
let line_end=$line_start+4 
awk "{ if (NR>=$line_start && NR<=$line_end) print; }" file

Another awk solution (s.awk):

BEGIN           { v = -1} 
/regex/         { v = 0 } 
v > -1          { v++   }
v > -1 && v < 5 { print }
v == 5          { exit  }

use:

awk -f s.awk file
Share:
17,573
user1639103
Author by

user1639103

Updated on June 14, 2022

Comments

  • user1639103
    user1639103 almost 2 years

    Hi I'm trying to print the 5 lines after a regular expression has been found using the awk command. I have the following:

    line_start=$(awk '/regex/{print NR}' file)
    let line_end=$line_start+4
    awk 'NR==$line_start, NR==$line_end' file
    

    This does not print anything. It doesnt hang, just goes on the next line.

    I researched some similar problems, and saw people use the -v option. Am I supposed to use that here, their situations were for larger awk scripts.

    By the way, I am using Kornshell

    Thanks!

  • SourceSeeker
    SourceSeeker over 11 years
    In most cases in the code you posted, if isn't necessary. Just put the condition outside the action block. This is what the OP tried to do and what Gilles does in his answer.
  • user1639103
    user1639103 over 11 years
    Thanks a lot guys! I understand a lot more now!
  • user1639103
    user1639103 over 11 years
    Wow! you guys are awesome thanks a lot! I didn't have all of this info available. Very detailed answer thanks!