使用AWK抓住第n次出现在图案的两个之间或sed的(Grab nth occurrence in b

2019-07-03 16:14发布

我有,我想通过从文件输出解析的问题,我想抓住在图案的两个之间的文本的第n次出现最好用awk或sed的

category
1
s
t
done
category
2
n
d
done
category
3
r
d
done
category
4
t
h
done

远的不说这个例子,我想抓住的类别和done之间文本的第三次出现,本质上是输出会

category
3
r
d
done

Answer 1:

这可能会为你工作(GNU SED):

'sed -n '/category/{:a;N;/done/!ba;x;s/^/x/;/^x\{3\}$/{x;p;q};x}' file

通过关闭自动打印-n选项。 收拾行之间categorydone 。 存储在保持空间的计数器,当它到达3打印集合中的模式空间和退出。

或者如果你喜欢AWK:

awk  '/^category/,/^done/{if(++m==1)n++;if(n==3)print;if(/^done/)m=0}'  file


Answer 2:

试着这样做:

 awk -v n=3 '/^category/{l++} (l==n){print}' file.txt

或者更神秘:

awk -v n=3 '/^category/{l++} l==n' file.txt

如果你的文件大:

awk -v n=3 '/^category/{l++} l>n{exit} l==n' file.txt


Answer 3:

如果您的文件不包含任何空字符,这里的使用方式GNU sed 。 这将找到一个模式范围的第三次出现。 然而,你可以很容易地修改此得到任何你想要的发生。

sed -n '/^category/ { x; s/^/\x0/; /^\x0\{3\}$/ { x; :a; p; /done/q; n; ba }; x }' file.txt

结果:

category
3
r
d
done

说明:

关闭默认打印与-n开关。 在一行的开始匹配单词“类”。 SWAP与保持空间模式空间和空字符追加到模式的开始。 在这个例子中,如果模式则包含了两个主要空字符,拉出来模式的holdspace。 现在创建一个循环,直到最后一个模式匹配打印模式空间的内容。 当这最后的模式被发现, sed将退出。 如果它没有找到sed将继续读取输入的下一行,并继续在其循环。



Answer 4:

awk -v tgt=3 '
/^category$/ { fnd=1; rec="" }

fnd {
   rec = rec $0 ORS
   if (/^done$/) {
      if (++cnt == tgt) {
         printf "%s",rec
         exit
      }
      fnd = 0
   }
}
' file


Answer 5:

随着GNU awk的,你可以设置的记录分隔符正则表达式:

<file awk 'NR==n+1 { print rt, $0 } { rt = RT }' RS='\\<category' ORS='' n=3

输出:

category 
3
r
d
done

RT是匹配的记录分隔符。 需要注意的是相对于记录n将由一个作为第一个记录是指第一什么先被关闭RS

编辑

按埃德的评论,当记录在它们之间有其它的数据,这将无法正常工作,例如:

category
1
s
t
done
category
2
n
d
done

foo

category
3
r
d
done

bar
category
4
t
h
done

要解决这个问题的方法之一是清理输入与第二(或第一)AWK:

<file awk '/^category$/,/^done$/' |
  awk 'NR==n+1 { print rt, $0 } { rt = RT }' RS='\\<category' ORS='' n=3

输出:

category 
3
r
d
done

编辑2

埃德在评论中指出,上述方法不搜索结局模式。 这样做的一种方式,这还没有被覆盖的其他的答案,是用getline (注意,有一些注意事项使用awk函数getline):

<file awk '
  /^category$/ {
    v = $0
    while(!/^done$/) { 
      if(!getline) 
        exit
      v = v ORS $0
    }
    if(++nr == n) 
      print v
}' n=3

在一行:

<file awk '/^category$/ { v = $0; while(!/^done$/) { if(!getline) exit; v = v ORS $0 } if(++nr == n)  print v }' n=3


文章来源: Grab nth occurrence in between two patterns using awk or sed
标签: shell sed awk