sed 或 awk:删除模式后面的 n 行
Posted
技术标签:
【中文标题】sed 或 awk:删除模式后面的 n 行【英文标题】:sed or awk: delete n lines following a pattern 【发布时间】:2011-05-22 18:29:35 【问题描述】:如何在 sed(或任何类似工具 - 例如 awk)中混合模式和数字范围?我想要做的是匹配文件中的某些行,并在继续之前删除接下来的 n 行,我想将其作为管道的一部分。
【问题讨论】:
【参考方案1】:我会试试看的。
删除模式后的5行(包括有模式的行):
sed -e '/pattern/,+5d' file.txt
删除模式后的5行(不包括有模式的行):
sed -e '/pattern/n;N;N;N;N;d' file.txt
【讨论】:
请注意,+N
模式是 GNU 扩展。在第二个示例中将第一个 n
更改为 N
以使其包含带有模式的行。
模式匹配后如何删除所有行?我正在使用 sed -e '/
/,$d' out.txt 但它给出错误提示: sed: -e expression #1, char 24: extra characters after提前致谢。
发生的情况相似,但在每种情况下略有不同。在第一个配方中,/pattern/,+5
定义了一个范围,该范围以包含“模式”的行 (/pattern/
) 开始,并在 5 行之后结束 (+5
)。最后一个字符d
是在该范围内的每一行上运行的命令,即“删除”。在第二个配方中,它不是匹配范围,而是仅匹配包含模式 (/pattern/
) 的行,然后运行一系列命令:n;N;N;N;N;d
,它基本上打印下一行 (n
),然后读取并最终丢弃接下来的 4 行 (N;N;N;N;d
)。
在 Mac/OS X 系统上,您需要在右括号前添加一个分号:sed -e '/pattern/n;N;N;N;N;d;' file.txt
在第二种风格中,如何为接下来的 N 行指定一个数字。我必须删除接下来的 52 行,所以写 52 次 N;
很乏味。【参考方案2】:
没有 GNU 扩展(例如在 macOS 上):
删除一个图案后的5行(包括有图案的那一行)
sed -e '/pattern/N;N;N;N;d;' file.txt
添加-i ''
就地编辑。
【讨论】:
【参考方案3】:简单的awk
解决方案:
假设用于查找匹配行的正则表达式存储在 shell 变量 $regex
中,要跳过的行数存储在 $count
中。
如果匹配的行应该也被跳过($count + 1
行被跳过):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex skip=count; next --skip >= 0 next 1'
如果匹配的行不应该被跳过($count
行匹配被跳过):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex skip=count; print; next --skip >= 0 next 1'
说明:
-v regex="$regex" -v count="$count"
定义了基于 shell 同名变量的awk
变量。
$0 ~ regex
匹配感兴趣的行
skip=count; next
初始化跳过计数并继续下一行,有效跳过匹配行;在第二种解决方案中,next
之前的 print
确保它不被跳过。
--skip >= 0
减少跳过计数并在它(仍然)>= 0 时采取行动,这意味着应该跳过手头的行。
next
继续下一行,有效地跳过当前行
1
是 print
的常用简写;也就是简单地打印当前行
只有不匹配和未跳过的行才能到达此命令。
1
等价于 print
的原因是1
被解释为根据定义始终评估为真的布尔模式,这意味着其关联的操作(块)是无条件执行的。由于在这种情况下没有相关操作,awk
默认打印行。
【讨论】:
【参考方案4】:这可能对你有用:
cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2//!d|' pattern_number.txt |
sed -f - <(seq 21)
1
2
3
4
5
9
10
12
13
14
15
21
【讨论】:
一个聪明的(尽管是 GNU-Sed 特定的)解决方案,但很少有人会从中受益,除非您添加解释。pattern_number.txt
是一个 2 列文件,第一列包含要匹配的模式,第二列包含要跳过的行数。第一个sed
命令将文件转换为执行相应匹配和跳过的sed
脚本;该脚本通过-f
和stdin (-
) 提供给第二个sed
命令。第二个sed
命令对由seq 21
的输出形成的示例临时输入文件进行操作,以证明它有效。
此外,该解决方案有一个警告:它使用 not 跳过第一行(与模式匹配的行)的方法也有不跳过 重复范围内的行。
这是一个令人印象深刻的 sed 用法。【参考方案5】:
使用 Perl
$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN$y=1 $y=$. if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$
【讨论】:
【参考方案6】:此解决方案允许您将“n”作为参数传递,它将从文件中读取您的模式:
awk -v n=5 '
NR == FNR pattern[$0]; next
for (patt in pattern)
if ($0 ~ patt)
print # remove if you want to exclude a matched line
for (i=0; i<n; i++) getline
next
print
' file.with.patterns -
名为“-”的文件表示 awk 的标准输入,因此适合您的管道
【讨论】:
awk 比我想象的更像 perl!以上是关于sed 或 awk:删除模式后面的 n 行的主要内容,如果未能解决你的问题,请参考以下文章