按照模式删除 n 行

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

120997 次浏览

我来试试这个。

在一个模式后面删除5行(包括带有该模式的行) :

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

在一个模式后面删除5行(不包括带有该模式的行) :

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

这个解决方案允许您将“ 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 的 stdin,因此这适合您的管道

这可能对你有用:

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

简单的 awk解决方案:

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

如果跳过 应该跳过匹配行 < em > also ($count + 1行) :

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

如果 应跳过匹配行 < em > not ($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 }初始化跳过计数并继续到下一行,有效地跳过匹配的行; 在第2个解决方案中,next之前的 print确保跳过了 没有
    • --skip >= 0递减跳过次数,如果跳过次数(仍然) > = 0,则执行操作,这意味着应该跳过手边的行。
    • { next }继续到下一行,有效地跳过当前行
  • 1{ print }常用的简写,也就是说,当前行只是打印出来的
    • 只有不匹配和未跳过的行才能到达此命令。
    • 1等价于 { print }的原因是,1被解释为一个布尔模式,根据定义,它总是计算为 true,这意味着它的关联操作(块)是无条件执行的。因为在这种情况下有 没有相关的操作,所以 awk默认为 印刷行。

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

在一个模式后面删除5行(包括带有该模式的行)

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

添加 -i ''就地编辑。

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