如何使用sed提取两个模式之间的行并在循环中进行后处理?

4
我希望做类似于这样的事情。假设我有以下文本:
Start-pattern  
orange  
apple  
grape  
orange  
orange  
End-pattern  
#######  
bla bla bla  
########  
Start-pattern  
orange  
apple  
grape  
apple  
orange  
End-pattern  
#######
bla bla bla
########
Start-pattern  
orange  
orange  
orange  
End-pattern  
#######  
bla bla bla  
########

我希望在每个开始模式结束模式之间打印出有多少个橙子,苹果和葡萄。
在上面的例子中,在第一个开始模式和结束模式之间有3个"orange",1个"apple"和1个"grape"。在第二个SP和EP之间有2个"orange",2个"apple"和1个"grape",以此类推。
等待您宝贵的答案。

1
你能否为了清晰起见,在问题中添加完整的预期输出? - Sundeep
2个回答

3
您可以尝试使用以下的awk命令:
awk '$1 ~ /^Start-pattern$/{p=1;next} $1 ~ /^End-pattern$/{p=0; for (var in a) {print var,a[var];a[var]=""}; print "######"; next} p{a[$1]++}' file

更易读的 awk 代码:
$1 ~ /^Start-pattern$/ {
    p=1;
    next
}
$1 ~ /^End-pattern$/ {
    p=0;
    for (var in a) {
        print var,a[var];
        a[var]=""
    }
    print "######";
    next
} 
p {
    a[$1]++;
}

解释:

我们可以将这个 awk 分成三个代码块。

  1. 检查 Start-pattern 模式,然后启用 p=1
  2. 检查 End-pattern 模式,然后禁用 p=0。然后,打印带有相应计数的 a[]
  3. 这将在关联数组中存储这两个模式之间每个项的出现次数。

非常感谢。我会尝试一下。您能否请解释一下它是如何工作的?这将非常有帮助。 - Ashok Kumar

2
这可能适用于您(使用GNU sed、echo、sort和uniq):
sed -nr '/Start/,/End/!b;/Start/h;//!H;/End/!b;x;s/^[^\n]*\n(.*)\n.*/echo "\1"|sort|uniq -c/e;s/\n//g;p' file

使用-n命令打开类似于自然语言的sed grep。将StartEnd之间的行存储在保留空间(HS)中,并在遇到End字符串时,从HS替换模式空间(PS)。删除起始和结束头/尾,并使用替换命令的评估标志;将包含的行回显到排序中,然后使用uniq命令计算唯一行数。删除任何换行符并打印PS的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接