我正在尝试使用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
块上打印它。这样,您可以控制块本身,而不仅仅是特定的行。我会将数据存储在数组中,等等。