/start/、/end/range表达式在awk中有用吗?

/start/、/end/range表达式在awk中有用吗?,awk,Awk,我一直主张,您不应使用以下范围表达式: /start/,/end/ 在awk中,因为虽然它使您只想打印匹配文本(包括起始行和结束行)的情况比备选方案略为简单*: /start/{f=1} f{print; if (/end/) f=0} 当您想稍微调整它来做其他事情时,它需要完全重新编写,否则会导致重复的或不需要的代码。e、 g.如果要使用上面的第二个表单打印不包括范围分隔符的匹配文本,只需调整它以移动组件: f{if (/end/) f=0; else print} /start/{f=1

我一直主张,您不应使用以下范围表达式:

/start/,/end/
在awk中,因为虽然它使您只想打印匹配文本(包括起始行和结束行)的情况比备选方案略为简单*:

/start/{f=1} f{print; if (/end/) f=0}
当您想稍微调整它来做其他事情时,它需要完全重新编写,否则会导致重复的或不需要的代码。e、 g.如果要使用上面的第二个表单打印不包括范围分隔符的匹配文本,只需调整它以移动组件:

f{if (/end/) f=0; else print} /start/{f=1}
但是如果你从
/start/,/end/
开始,你就需要放弃这种方法,转而使用我刚刚发布的内容,否则你就必须编写如下内容:

/start/,/end/{ if (!/start|end/) print }
i、 e.重复不需要的条件

然后我看到了一个问题,需要识别文件中最后一个
结尾
,以及在解决方案中使用范围表达式的位置,我认为这似乎有一定的价值(请参阅)

不过,现在我又开始想,根本不值得为范围表达式费心,一个不使用范围表达式的解决方案在这种情况下也同样有效

那么,有没有人举过一个例子,说明范围表达式实际上为解决方案增加了显著的价值

*我曾经用过:

/start/{f=1} f; /end/{f=0}
但是很多时候,我发现当
f
为真并且
/end/
被发现时,我不得不做一些额外的事情(或者换一种方式说,如果
f
为真,我只需要在
/end/
被发现时做一些事情),所以现在我只想坚持稍微不那么简短但更健壮和可扩展的:

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

有趣。我也经常从范围表达式开始,然后切换到使用变量

我认为,除了纯范围之外,这种情况可能很有用,唯一的情况是,如果您想要打印匹配,但仅当它位于某个范围内时。也因为它的作用是显而易见的。例如:

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

但是它比较长,可读性也比较差。

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

那么,有没有人举过一个例子,说明范围表达式实际上为解决方案增加了显著的价值

在提到的用例中,范围表达式提高了易读性。下面是一些示例,其中范围表达式精确地选择要处理的文本。这些只是一手例子,但有无数类似的应用程序,展示了awk不可思议的多功能性

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

awk '/^2015-06-30T12:00:00Z/,/^2015-06-30T13:00:00Z/'
从文件中提取文档 这可用于将资源与shell脚本捆绑(使用cat),提取部分GPG签名消息(使用
--clearsign
准备)或更一般的MIME消息

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

awk '/begin{abstract}/,/end{abstract}/' *.tex
或者所有的定理,准备一个定理数据库

awk '/begin{theorem}/,/end{theorem}/' *.tex
或者写一篇短文,确保定理不包含引用(如果我们认为这是糟糕的风格):


或者预处理表格等。

好的,我会考虑一下,谢谢您的回复。默认情况下,我会使用
/start/{f=1}f{if(/ppp/)print;if(/end/)f=0}
,因为这是对我的基本解决方案
/start/{f=1}f{print;if(/end/)f=0}
)的明显增强。+1:我还发现了一些简单的事情,例如,我们可以通过说
awk'/patt/,从模式打印到文件末尾,0'file
而不是执行
awk'/patt/{p=1}p'file
我将此答案标记为接受,因为我认为最终这并不是什么大问题,如果有时人们更喜欢使用范围表达式作为起点,至少当需求发生变化,不再有意义时,这会立即发生,这样他们就不会有那么多代码需要重新编写。这还意味着您可以编写一个看起来像等效sed解决方案的awk解决方案,因此它可能会帮助人们避免被诱惑去增强sed解决方案来完成一些复杂的事情。谢谢大家的回复。@EdMorton。谢谢,谢谢你的讨论,我觉得很有趣。您建议的标准方法
/start/{f=1}f{print;if(/end/)f=0}
完美地模仿了
/start/,/end/
,而其他方法可能更接近。因此,我认为这是一个很好的代码使用,如果你想能够扩展它以后不重写…我只是最近才了解范围表达式,我喜欢他们!当然,“flag”变量做不到的事情是它们做不到的,但我认为它们是有用的。诚然,在使用
f
时,你减少了(一种)重复,但在这样做时,你承担了在记录之间跟踪
f
的责任。这实际上意味着,为了理解脚本,您必须(至少)阅读两次,而不是一次。@TomFenech您如何处理增强脚本,例如,不打印开始/结束行?扔掉原来的,用一个变量重新开始,或者在动作块中用
if
或其他什么引入开始/结束条件的复制?我对范围表达式的关注是,如果/当您的需求发生变化时,我没有合理的方法来建立它。我认为没有任何问题
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) }
'