在AWK命令中将变量传递给NR不起作用

时间:2012-08-31 15:40:59

标签: shell unix awk ksh

您好我正在尝试使用awk命令找到正则表达式后打印5行。我有以下内容:

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

这不会打印任何内容。它没有挂起,只是继续下一行。

我研究了一些类似的问题,并看到人们使用-v选项。我应该在这里使用它,他们的情况是更大的awk脚本。

顺便说一下,我正在使用Kornshell

谢谢!

2 个答案:

答案 0 :(得分:9)

您的脚本存在一些问题。直接的问题是在第二次调用awk时,你在脚本周围使用单引号,因此$line_start$line_end是由shell扩展的变量,它们作为脚本的一部分逐字传递给AWK。您可以通过使用双引号来解决此问题。

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

这仅适用于$line_start$line_end是数字。如果它们是字符串,则无法执行此操作,因为shell变量的值最终会被awk解析为awk代码的一部分,而不是字符串。通常,要将字符串传递给awk脚本,可以使用带有-v的惯用法来定义与shell变量同名的awk变量(如果您愿意,可以使用不同的名称):

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

您的脚本存在更多问题。

  • 您解析文件两次。如果文件很大,这可能会很慢,如果数据来自管道而不是磁盘文件则不可能。
  • 如果/regex/匹配多个,则$line_start将包含一个行号列表。 shell会在let行上抱怨语法错误。

如果你想在匹配后显示5行,请在awk中进行计数。

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

如果您只想显示第一个匹配的块,请在show_lines达到0后退出。

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

答案 1 :(得分:2)

您可以使用sed:

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

或者更改awk解决方案:

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

另一个awk解决方案(s.awk)

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

使用:

awk -f s.awk file