2012-08-31 86 views
3

嗨我试图在使用awk命令找到正则表达式之后打印5行。我有以下内容:在AWK命令中将变量传递给NR不起作用

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

这不会打印任何内容。它不挂,只是在下一行。

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

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

谢谢!

回答

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到具有相同名称的定义AWK的变量,如shell变量(或以不同的名称,如果你喜欢):

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; } 
+0

哇!你们真棒,非常感谢!我没有提供所有这些信息。非常详细的答案谢谢! – user1639103

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 
+0

我得到这个 – user1639103

+0

什么是错误的错误? – perreal

+0

在大多数情况下,您发布的代码中不需要“if”。只需将条件放在操作块外面即可。这是OP试图做的事情,以及Gilles在他的回答中做了什么。 –