Awk在两个模式之间提取最少匹配的内容

时间:2016-08-12 08:42:10

标签: regex shell awk pattern-matching

假设我有一行文件:

db.collection.aggregate([
    {$group: {_id: "$relate_id", userid: {"$push": "$userid"}}},
]
)

当我执行a1 - first match /a/ b - other stuff a2 - last match /a/ b c - first match /c/ c - last match /c/ 时,我会得到

awk '/a/,/c/' file

我想要做的是获得/ a /和/ c /之间的中间部分。但模式/ a /和/ c /匹配几行,在这些行之间还有其他一些东西。所以我想知道是否有一种简单的方法来得到这样的结果:

a1 - first match /a/
b - other stuff
a2 - last match /a/
b
c - first match /c/

3 个答案:

答案 0 :(得分:1)

您无法使用范围表达式执行此操作。您需要匹配a并开始收集变量中的行。如果您遇到另一个a,则必须清除该变量并重新开始。最后,当您看到c时,您打印变量。

awk '/^a/ { var = $0; flag = 1; next }
     flag { var = var "\n" $0 }
     /^c/ && flag { print var; flag = 0; var = "" }' file

答案 1 :(得分:0)

由于你没有办法知道哪个是最后一次出现模式,直到你读完所有文件,最好经历两次:第一次得到匹配的行号第二个打印那些内容:

awk 'FNR==NR && /^a/ {p1=FNR; next}         # last match of /a/
     FNR==NR && /^c/ && !p2 {p2=FNR; next}  # first match of /c/
     (FNR >= p1) && (FNR <= p2)' file file

使用技巧FNR==NR区分第一个循环和第二个循环,如Idiomatic awk中所述。

使用此文件返回:

$ awk 'FNR==NR && /^a/ {p1=FNR; next} FNR==NR && /^c/ && !p2 {p2=FNR; next} (FNR >= p1) && (FNR <= p2)' file file
a2 - last match /a/
b
c - first match /c/

答案 2 :(得分:0)

数组中的另外awk个累积行

$ awk '/^a/{delete a; c=0; p=1} 
          p{a[++c]=$0} 
       /^c/{for(k=1;k<=c;k++) print a[k]; exit}' file

a2 - last match /a/
b
c - first match /c/