我正在尝试找到一种方法来 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
-----
#