首页 > 解决方案 > sed - 从 pattern2 之前的 pattern1 删除到 pattern2 之后的 pattern3

问题描述

我正在尝试删除两个模式之间的线条,包括带有模式本身的线条,如果在它们之间找到另一个模式,但我不知道如何解决它。

假设我有如下输入,并且想要删除第 6 行到第 11 行,因为在模式和notthis之间找到了模式:startend

start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
OgytsRhZbD8T
notthis
0PlcUh2RLvVW
tsz2S80SyW9p
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

我将我认为我从这个答案中理解的内容更改为类似的内容,但它不起作用:

/^start$/{$!{N;/^start\n(.*\n)*notthis.*\n(.*\n)*end/d;ty;P;D;:y}}

是因为N只将初始模式后面的行附加^start$到模式空间而忽略了后面的内容吗?什么是实现我想要实现的目标的正确方法?

标签: regexawksedmultiline

解决方案


sed 用于对单个字符串进行简单替换,仅此而已。对于您应该使用 awk 的任何其他内容,例如,对于 mult-char RS 的 GNU awk,这个简短的脚本将从您发布的输入中产生您想要的输出:

$ awk 'BEGIN{RS=ORS="end\n"} !/notthis/' file
start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

或者更清晰,更健壮,更容易用任何 awk 增强:

$ cat tst.awk
/start/ { f = 1 }
f {
    rec = rec $0 ORS
    if ( /end/ ) {
        if ( rec !~ /notthis/ ) {
            printf "%s", rec
        }
        rec = ""
        f = 0
    }
}
$
$ awk -f tst.awk file
start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

以上将在每个 UNIX 机器上的任何 shell 中使用任何 awk 有效且稳健地工作,如果/当您的需求发生变化时,易于理解和修改。


推荐阅读