awk范围和文本选择

时间:2017-05-15 15:06:46

标签: awk

我知道如何在awk中使用范围运算符

awk '/start/,/stop/' file

是否可以在范围运算符中选择文本? ATM,我正在使用if语句

awk '/start/,/stop/ { if ($1~/foo/) { } }' file

是否有一种更为自觉的方式呢?

2 个答案:

答案 0 :(得分:1)

永远不要使用范围表达式,因为它使得琐碎的工作变得非常简单,但是当任务变得更有趣时,需要完全重写或复制条件。

而不是:

awk '/start/,/stop/' file

使用:

awk '/start/{f=1} f{print} /stop/{f=0}' file

然后您想做的事情变得简单:

awk '/start/{f=1} f{ if ($1~/foo/) { } } /stop/{f=0}' file

我假设你在空{ }内有一些想法。

答案 1 :(得分:1)

你提出的建议确实有效:

$ seq 1 15 | awk '/^6/,/^9/ { if ($1~/8/){print} else print "in range but not 8" }'
in range but not 8
in range but not 8
8
in range but not 8

但正如埃德莫顿所说,这是一个脆弱的结构。

例如,,是最低优先级,您可能会因为这不起作用而不知所措:

$ echo "this one print" | awk '/^1/ , /^55/ || /this/'  

另一个例子。假设你有:

$ echo "a
b
c
---
d
e
f
---
g
h"

尝试使用范围运算符来包含或排除---之间的所有内容。它是tricky,因为起始和结束标记是相同的,并且可以set and reset在同一行上的范围。

如果你训练你的肌肉记忆不能/^x/ , /^y/,而是做/^x/{flag=1} flag{whatever} /^y/{flag=0},那么就不再有头疼了:

$ echo "this one print" | awk '/^1/{flag=1} flag || /this/{print} /^55/{flag=0}'
this one print

或者,

$ echo "a
b
c
---
d
e
f
---
g
h" | awk '/^---$/{f= ! f; next}  f'
d
e
f

(如果您想要从包含排除到排除,只需在结尾处更改为! f。)

因此,一般来说,您可以对范围和子范围执行此操作:

awk '/^start/ || /^end/{f= ! f; next} /e/ && f { what you do in sub range }' file

         ^         ^                            can be a single regex if same pattern
                                 ^              remove next to include in processing
                                      ^         applies to within range /start/,/end/
                                          ^  ^     because of the flag