有没有办法限制 awk 中范围模式的范围?

有没有办法限制 awk 中范围模式的范围?

我正在尝试使用awk范围模式来查找select一组文件中的所有 SQL 语句,灵感来自这个 stackoverflow 答案

awk手册中:

表达式的形式pattern1, pattern2称为范围模式。它匹配以匹配 的记录开始的所有输入记录pattern1,一直到匹配 的记录 pattern2(包含在内)。

我最初的尝试是

awk '/select/,/from/' *

在这种情况下,*仅代表大量不同的文件。

这会在 HTMLselect标签上返回一些错误的命中,因此我将命令改进为

awk '/[^<]select[^>]/,/from/' *

这似乎消除了大部分点击。

然而,我仍然会因评论中出现的“select”一词而得到一些错误的命中,并且这些命中在最终命中“from”或文件末尾之前,每条命中都会产生很多行噪音。我想要的是,如果“select”和“from”之间的行数超过 10 行,则范围模式不会注册匹配项。

pattern1我的问题是:如果 的匹配项和 的匹配项之间的行数pattern2超过给定阈值,我是否可以使范围模式无法匹配?如果是,如何实现?

答案1

范围模式很有用,但不灵活。不要使用它们,而是在变量中维护介于或不之间的状态。 awk 脚本/select/,/from/相当于

/select/ {printing = 1}
printing {print}
/from/ {printing = 0}

如果要将范围限制为多行,请维护所见行的计数器并累积输出,直到您决定是否显示它。

/select/ {select_text = $0; select_line_count = 1;}
select_line_count {select_text = select_text "\n" $0}
/from/ {if (select_line_count <= 10) {print select_text; print}
        select_line_count = 0}

您可能需要优化该模式,例如要求select位于行首(空白除外),并且后跟空白:/^[\t ]*select($|[\t ])/

答案2

/pattern1/,/pattern2/您可以根据需要扩展条件,方法是{}在发生这种情况时添加一个要执行的块:

例如,看看我们如何打印 50 到 70 之间的数字,但只打印每个块的前 5 个匹配项:

$ seq 200 | awk '/50/,/70/ {if ($0~/50/) {c=0}; if (c++ <= 5) print}'
50
51
52
53
54
55
150
151
152
153
154
155

对于您的情况,您可能想说这样的话,这将打印匹配的前 10 行。

awk '/[^<]select[^>]/,/from/ {if (c++ <= 10) print}' *

更复杂的解决方案包括存储所有这些输出,然后在END块上打印它。这样,您可以控制块本身,而不仅仅是特定的行。我会将数据存储在数组中,等等。

相关内容