ChatGPT解决这个技术问题 Extra ChatGPT

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

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


d
dogbane

我会试一试。

删除模式后的 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
为了完整起见:删除遵循特定模式的所有行 something 执行:sed -E '/^something$/,$d',其中 -E 是 POSIX 可移植性扩展正则表达式。
t
thakis

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

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

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

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


关于如何在比赛前后完全删除几行的任何想法?找不到任何合适的 POSIX 变体。
m
mklement0

简单的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 ~ 正则表达式匹配感兴趣的行 { skip=count; next } 初始化跳过计数并继续到下一行,有效地跳过匹配行;在第二个解决方案中,下一个之前的打印确保它不会被跳过。 --skip >= 0 减少跳过计数,如果它(仍然)>= 0 则采取行动,这意味着应该跳过手头的行。 { next } 进入下一行,有效地跳过当前行

{跳过=计数; next } 初始化跳过计数并继续到下一行,有效地跳过匹配行;在第二个解决方案中,下一个之前的打印确保它不会被跳过。

--skip >= 0 减少跳过计数,如果它(仍然)>= 0 则采取行动,这意味着应该跳过手头的行。

{ next } 进入下一行,有效地跳过当前行

是 { print } 的常用简写;也就是说,当前行只是简单地打印只有非匹配和非跳过的行到达这个命令。 1 等价于 { print } 的原因是 1 被解释为布尔模式,根据定义,该模式始终评估为 true,这意味着其关联的操作(块)是无条件执行的。由于在这种情况下没有关联的操作,awk 默认打印该行。

只有不匹配和未跳过的行到达此命令。

1 等价于 { print } 的原因是 1 被解释为布尔模式,根据定义,该模式始终评估为 true,这意味着其关联的操作(块)是无条件执行的。由于在这种情况下没有关联的操作,awk 默认打印该行。


p
potong

这可能对您有用:

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 的输出形成的示例 ad-hoc 输入文件进行操作,以证明它可以工作。
此外,该解决方案有一个警告:它使用的不跳过第一行(与模式匹配的行)的方法具有也不会跳过范围内重复行的副作用。
这是 sed 的一个令人印象深刻的用法。
s
stack0114106

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

g
glenn jackman

此解决方案允许您将“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!