awk中的/ start /,/ end / rangeexpression式有用吗?
我一直主张,你不应该使用如下的范围expression式:
/start/,/end/
在awk中,因为虽然它使得你只想打印匹配的文本,包括开始和结束行稍微比替代*更简单的情况:
/start/{f=1} f{print; if (/end/) f=0}
当你想稍微修改它来做任何事情时,它需要完整的重写或者导致重复的代码或其他不合需要的代码。 例如,如果要使用上面的第二种forms打印除范围分隔符之外的匹配文本,则只需调整它即可移动组件:
f{if (/end/) f=0; else print} /start/{f=1}
但是如果你开始使用/start/,/end/
你需要放弃这个方法来支持我刚刚发布的内容,或者你必须写下如下内容:
/start/,/end/{ if (!/start|end/) print }
即重复不合要求的条件。
然后我看到一个发布的问题,需要在文件中标识最后的end
,并且在解决scheme中使用了范围expression式,我认为这似乎可能有一些价值(请参阅https://stackoverflow.com/a/21145009/ 1745001 )。
但是现在,我又回想到,根本不值得使用范围expression式,而不使用范围expression式的解决scheme在这种情况下也能起作用。
所以 – 有没有人有范例expression式实际上增加一个解决scheme明显的价值?
*我曾经使用:
/start/{f=1} f; /end/{f=0}
但是太多的时候,我发现我不得不另外做一些额外的事情,当f
是真的和/end/
被发现(或换一种方式,只有做一些事情/end/
被发现如果f
是真的),所以现在我只是试图坚持稍微简短一点,但更健壮和可扩展:
/start/{f=1} f{print; if (/end/) f=0}
有趣。 我也经常从范围expression式开始,然后切换到使用variables..
我认为这种情况可能是有用的,除了纯粹的范围情况,如果你想打印一个比赛,但只有在一定的范围内。 也因为它立即显而易见。 例如:
awk '/start/,/end/{if(/ppp/)print}' file
用这个input:
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
但时间更长,可读性更差
尽pipe/start/,/end/
rangeexpression式可以很容易地用一个条件来重新实现,但是它有很多有用的用例。 正如你观察到的那样,对于表格数据的处理可能没有什么价值, awk的主要但不仅仅是用例。
所以 – 有没有人有范例expression式实际上增加一个解决scheme明显的价值?
在上述用例中,范围expression式提高了易读性。 以下是一些示例,其中范围expression式准确地select要处理的文本。 这些只是一个例子,但有无数类似的应用程序,展示awk令人难以置信的多function性。
在一定时间范围内过滤日志
假设每个日志行以ISO时间戳开始,则下面的filter将select1小时给定范围内的所有事件:
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环境,所以我们可以select我们目录中所有文章的摘要:
awk '/begin{abstract}/,/end{abstract}/' *.tex
或所有的定理,准备一个定理数据库!
awk '/begin{theorem}/,/end{theorem}/' *.tex
或写一个短语确保定理不包含引用(如果我们认为这是不好的风格):
awk ' /begin{theorem}/,/end{theorem}/ { if(/\\cite{/) { c+= 1 } } END { printf("There were %d bad-style citations.\n", c) } '
或预处理表格等