关于unix:sed或awk:删除模式后面的n行

sed or awk: delete n lines following a pattern

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


我会去看看。

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

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

要在图案后删除5行(不包括带图案的行):

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


简单的awk解决方案:

假设用于查找匹配行的正则表达式存储在shell变量$regex中,并且要在$count中跳过要跳过的行数。

如果还应跳过匹配行(跳过$count + 1行):

1
2
... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

如果不应跳过匹配的行(跳过匹配后的$count行):

1
2
... | 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被解释为布尔模式,根据定义,它总是求值为true,这意味着它的关联动作(块)是无条件执行的。由于在这种情况下没有关联的操作,awk默认为打印该行。


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

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

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

添加-i ''进行就地编辑。


使用Perl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ 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
$

这可能对你有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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


此解决方案允许您传递"n"作为参数,它将从文件中读取您的模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
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的stdin,因此这适用于您的管道