sed或awk:删除模式后的n行


105

如何在sed(或任何类似工具-例如awk)中混合模式和数字范围?我想要做的是匹配文件中的某些行,并在继续操作之前删除下n行,而我希望将其作为管道的一部分进行。

Answers:


186

我会去解决的。

要删除模式后的5行(包括带有模式的行):

sed -e '/pattern/,+5d' file.txt

要删除模式后的5行(不包括带有模式的行):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt

14
请注意,该+N模式是GNU扩展。在第二个示例中将第n一个更改为an N,以使其包含带有模式的行。
暂停,直到另行通知。

2
模式匹配后如何删除所有行?我正在使用sed -e'/ <!-#content end-> </ div> /,$ d'out.txt,但它给出了错误提示:sed:-e表达式#1,char 24:后面有多余字符命令预先感谢。
N mol

8
发生的情况相似,但在每种情况下都略有不同。在第一个配方中,/pattern/,+5定义一个范围,该范围以包含“ pattern”的行开始(/pattern/),然后以5行结束+5。最后一个字符d是在该范围内的每一行上运行的命令,即“删除”。在第二个配方中,它不匹配范围,而是仅匹配包含模式(/pattern/)的行,然后运行一系列命令:{n;N;N;N;N;d},该命令基本上会打印下一行(n),然后读取并最终丢弃接下来的4行(N;N;N;N;d)。
pimlottc

18
在Mac / OS X系统上,您需要在右方括号前添加分号:sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
AvL 2013年

1
出于完整性考虑:要删除遵循特定模式的所有行,请执行以下 something操作:sed -E '/^something$/,$d',其中-EPOSIX可移植性扩展正则表达式是。
not2qubit

7

没有GNU扩展(例如,在macOS上):

删除图案后的5行(包括带有图案的行)

 sed -e '/pattern/{N;N;N;N;d;}'

添加-i ''以就地编辑。


6

简单的awk解决方案:

假定用于查找匹配行的正则表达式存储在shell变量中$regex,而要跳过的行数也存储在shell变量中$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"awk基于同名的shell变量定义变量。
  • $0 ~ regex 符合兴趣线
    • { skip=count; next }初始化跳过计数并前进到下一行,有效地跳过匹配的行;在第二个解决方案中,printbefore next确保不会跳过它。
    • --skip >= 0 减少跳过计数并在(仍然)> = 0时采取措施,这意味着应跳过当前行。
    • { next } 前进到下一行,有效跳过当前行
  • 1是常用的简写{ print }; 也就是说,仅打印当前行
    • 只有不匹配和不跳过的行才能到达此命令。
    • 其原因1是相当于{ print }1被解释为布尔图案,根据定义总是评估为真,这意味着被无条件地执行其相关联的动作(块)。由于在这种情况下没有关联的操作,因此awk默认情况下将打印该行。

3

这可能对您有用:

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

10
哇,真是神秘。
pimlottc

3
一个聪明的(尽管特定于GNU-Sed的)解决方案,但是除非您添加解释,否则很少有人会从中受益。 pattern_number.txt是一个2列文件,在第1列中包含要匹配的模式,在第2列中包含要跳过的行数。第一个sed命令将文件转换为sed执行相应匹配和跳过操作的脚本;该脚本是通过-f和stdin(-)提供给第二个sed命令的。第二个sed命令对示例临时输入文件进行操作,该示例输入文件由的输出组成,seq 21以证明其有效。
mklement0

此外,该解决方案附带一个警告:它使用跳过第一行(与模式匹配的行)的方法也具有不跳过范围内重复行的副作用。
mklement0

sed令人印象深刻。
特拉维斯·罗德曼

3

使用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
$

2

此解决方案允许您传递“ 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的标准输入,因此适合您的管道


2
awk能够比我意识到的更像perl!
Martin DeMello 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.