6

嗨,我正在尝试在使用 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

谢谢!

4

2 回答 2

14

您的脚本有几个问题。直接的问题是,在第二次调用 awk 时,您在脚本周围使用单引号,因此$line_start$line_end是由 shell 扩展的变量,它们作为脚本的一部分按字面意思传递给 awk。您可以改用双引号来解决此问题。

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

这只是因为$line_start$line_end是数字。如果它们是字符串,则不能这样做,因为 shell 变量的值最终会被 awk 解析为 awk 代码的一部分,而不是字符串。通常,要将字符串传递给 awk 脚本,您可以使用 with-v来定义与 shell 变量同名的 awk 变量(如果您愿意,也可以使用不同的名称):

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

您的脚本存在更多问题。

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

如果要在匹配后显示 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; }
于 2012-08-31T16:12:37.360 回答
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
于 2012-08-31T15:46:24.177 回答