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 行的主要内容,如果未能解决你的问题,请参考以下文章

sed和awk用法

三剑客-sed awk

linux、 grep 、awk、sed 删除关键字的上一行

SedAwk单行脚本快速参考

sed 删除最后几行 和删除指定行 awk使用

sed,awk工具学习