Grep 多个模式并在每个模式下打印不同数量的行?

Grep 多个模式并在每个模式下打印不同数量的行?

我正在尝试找到一种方法来 grep/awk 多个模式,然后在第一个模式下方打印一定数量的行,在第二个模式下方打印一定数量的行。例如

  ....
  other lines
  ....
###Pattern 1####
line 1
line 2
line 3 
 ....
 other lines
 ....
####Pattern 2####
line 1
line 2
line 3 
line 4
 ....
 other lines
 ....

所以我想做的是找到文件中的两个模式,并打印出第一个模式和下面的前 3 行,然后打印第二个模式和第二个模式下面的前 4 行。

这样我想要的输出看起来像:

####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4

更新了所需的输出 因此,在我不太清楚之前,我道歉,可能有多种模式。所以我希望实现的是如下所示的输出:

####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4
-----
####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4
-----
 and so on

答案1

sed -ne'/pattern1/{:1' -e'$p;N;s/\n/&/[num]; to' -eb1 -e\} \
     -e'/pattern2/{:2' -e'$p;N;s/\n/&/[num]; to' -eb2 -e\} \
     -ed -e:o -eh      -e'y/\n-/-\n/;s/[^-]*//g' -e'H;x;p'

这将-在匹配块后面打印与该匹配后面的换行符一样多的破折号。因此,如果您希望在每个模式 1 匹配后有 4 行,在每个模式 2 匹配后有 2 行,那么您将在模式 1 块尾部的 4 个连字符和模式 2 尾部的 2 个连字符的每个块之间打印一条额外的分隔线堵塞。这都是真的除了当收集每个尾部时遇到最后一行时 - 在这种情况下,最后一行和模式匹配之间的所有内容都会被打印,但不会附加连字符。

您可能会注意到上面脚本中的大部分代码sed相当多余。基本上我们只是为每个可能的匹配实现相同类型的循环。sed正如上面所表明的,正是由于 的非常简单的语法规则,才使得脚本编写sed如此出色。换句话说,因为sed语法很基础,所以写一个能写sed脚本的脚本是一件简单的事情。

例如,此任务可以轻松参数化以处理任意数量的模式和关联的跟随行计数:

amatch(){  sed ${2:+"-ne$(n=0;                   \
    while  [ "$#" -gt "$((!!(n+=1)))" ];         \
    do     printf "\n/%s/{:$n\n\t%s;to\n\t%s\n}" \
                  "$1" "\$p;N;s/\n/&/$2" "b$n";  \
           shift 2;                              \
    done;  printf "\nd;:o\n\t%s\n\t%s\n\tH;x;p"  \
                  'h;y/\n-/-\n/' 's/[^-]*//g'    \
)"}; }

只要amatch()使用 2 个或更多参数调用,它就会构建一个sed与上面一样的脚本,并为每一对编写一个循环。

因此它首先在子 shell 中构建并打印sed脚本,然后sed针对 stdin 运行它。

所以当我这样做时:

seq 30 | amatch \[45] 5 1$ 2

shell 的 while 循环组装并打印出一个命令替换脚本,如下所示:

/[45]/{:1
    $p;N;s/\n/&/5;to
    b1
}
/1$/{:2
    $p;N;s/\n/&/2;to
    b2
}
d;:o
    h;y/\n-/-\n/
    s/[^-]*//g
    H;x;p

sed根据标准输入进行评估并打印......

1
2
3
--
4
5
6
7
8
9
-----
11
12
13
--
14
15
16
17
18
19
-----
21
22
23
--
24
25
26
27
28
29
-----

答案2

毫无疑问有一些更优雅的方法,但这是一种方法

# awk '/Pattern 1/{for(c=0;c<4;c++){print;getline}}/Pattern 2/{for(c=0;c<5;c++){print;getline}}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
#

稍微优雅一些​​:

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline}}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
#

要在匹配的集合下弹出 5 个连字符,请尝试以下操作

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline;x=1}if(x){print "-----";x=0}}' foo
###Pattern 1####
line 1
line 2
line 3
-----
####Pattern 2####
line 1
line 2
line 3
line 4
-----
#

或者在最后使用“-----”:

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline}}END{print "-----"}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
-----
#

相关内容