/ start /,/ end / range表达式在awk中是否有用?

时间:2014-05-29 13:25:43

标签: awk

我一直认为你绝不应该使用范围表达式,如:

/start/,/end/
在awk中的

因为虽然它使得你只想要打印匹配文本的简单情况,包括起始和结束行比替代*更简洁*:

/start/{f=1} f{print; if (/end/) f=0}

当你想稍微调整它以做任何其他事情时,它需要完全重写或导致重复或其他不合需要的代码。例如如果你想使用上面的第二个表格打印除范围分隔符之外的匹配文本,你只需调整它以移动组件:

f{if (/end/) f=0; else print} /start/{f=1}

但如果你从/start/,/end/开始,你需要放弃这种方法,转而支持我刚刚发布的内容,或者你必须写下这样的内容:

/start/,/end/{ if (!/start|end/) print }

即。复制不合需要的条件。

然后我看到发布了一个问题,要求在文件中标识最后end,并在解决方案中使用范围表达式,我认为这似乎有一些价值(参见https://stackoverflow.com/a/21145009/1745001 )。

现在,我现在又回想起根本不值得使用范围表达式,并且不使用范围表达式的解决方案在这种情况下也会起作用。

那么 - 有没有人有一个例子,其中范围表达式实际上为解决方案添加了显着的值?

*我曾经使用过:

/start/{f=1} f; /end/{f=0}

但是很多次我发现当f为真并找到/end/时我必须做一些额外的事情(或者换句话说只有在找到/end/时做某事f是真的)所以现在我只是试着坚持稍微不那么简短但更强大和可扩展的内容:

/start/{f=1} f{print; if (/end/) f=0}

2 个答案:

答案 0 :(得分:10)

有趣。我也经常从范围表达式开始,然后转而使用变量..

我认为这种情况可能有用,除了纯粹的范围情况之外,如果你想要打印一个匹配,但只有它在一定范围内。还因为它立即显而易见。例如:

awk '/start/,/end/{if(/ppp/)print}' file

使用此输入:

start
dfgd gd
ppp 1
gfdg
fd gfd
end
ppp 2 
ppp 3
start
ppp 4
ppp 5
end
ppp 6
ppp 7
gfdgdgd

将产生:

ppp 1
ppp 4
ppp 5

- 当然也可以使用:

awk '/start/{f=1} /ppp/ && f; /end/{f=0}' file

但它更长,可读性更差......

答案 1 :(得分:2)

虽然你是正确的/start/,/end/范围表达式可以很容易地用条件重新实现,但它有许多有趣的用例,它可以单独使用。正如您所观察到的那样,处理表格数据可能没什么价值,主要但不仅仅是 awk 的用例。

  

那么 - 有没有人有一个例子,其中范围表达式实际上为解决方案添加了显着的值?

在上述用例中,范围表达提高了易读性。以下是一些示例,其中范围表达式准确地选择要处理的文本。这些只是一些例子,但是有无数类似的应用程序,展示了 awk 令人难以置信的多功能性。

在一个时间范围内过滤日志

假设每个日志行都以ISO时间戳开头,下面的过滤器会选择给定1小时范围内的所有事件:

awk '/^2015-06-30T12:00:00Z/,/^2015-06-30T13:00:00Z/'

从文件中提取文档

awk '/---- begin file.data ----/,/---- end file.data ----/'

这可用于将资源与shell脚本(使用 cat )捆绑在一起,以提取部分GPG签名的消息(使用--clearsign准备)或更常见的MIME消息。

处理LaTeX文件

范围模式可用于匹配LaTeX环境,因此我们可以选择目录中所有文章的摘要:

awk '/begin{abstract}/,/end{abstract}/' *.tex

或所有定理,准备一个定理数据库!

awk '/begin{theorem}/,/end{theorem}/' *.tex

或写一个 linter 确保定理不包含引用(如果我们认为这是坏的风格):

awk '
  /begin{theorem}/,/end{theorem}/ { if(/\\cite{/) { c+= 1 } }
  END { printf("There were %d bad-style citations.\n", c) }
'

或预处理表,等。