删除包含两个字符串匹配的行

删除包含两个字符串匹配的行

如何从以下文件中删除所有包含defAND的行(第 2 行和第 4 行)?jkl我希望该匹配也适用于字段的子字符串匹配。文件中的字段以空格分隔。

$ cat test2.txt 
1. abc def ghi
2. def ghi jkl
3. jkl mno pqr
4. jkl def stu
5. vwx yza bcd

我设法使用布尔值OR( \|) 来做到这一点:

$ sed '/def.*jkl\|jkl.*def/d' test2.txt 
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

是否有更简单的布尔语法AND,例如$ sed '/defANDjkl/d'

我尝试了sed '/def&jkl/d'、、sed '/def&&jkl/d'和,但没有任何作用sed '/def\&jkl/d'sed '/def\&\&jkl/d'

答案1

具体来说sed,你可以这样做:

sed -e '/def/!b' -e /jkl/d

如果未找到 ( ),则第一个expressionb会溢出(因为我们没有传递该-n选项而打印该行),如果找到,则第二个eletes 会溢出。所以最后只有当 和 都被发现时,该行才会被删除。def!djkldefjkl

要推广到任意数量的正则表达式,您可以执行以下操作:

sed '
  /regexp1/!b
  /regexp2/!b
  /regexp3/!b
  d'

请注意,这\|不是一个标准基本正则表达式(BRE)运营商。很少sed有实现支持它。标准 BRE 既没有 OR 也没有 AND 运算符。标准 ERE(扩展正则表达式,正如sed -E许多sed实现所支持的那样)确实支持 OR ( |) 但不支持 AND。

ast-开放的实现中sed确实有一个 AND 运算符 ( &)增强的使用-A或启用正则表达式-X,但您需要:

sed -A '/.*def.*&.*jkl.*/d'

作为与和A&B都匹配的字符串上的匹配。AB

通过sed支持类似 perl 正则表达式的实现(例如sed -Past-open 或sed -Rwith ssed),您可以使用前瞻运算符:

sed -P '/^(?=.*def)(?=.*jkl)/d'

它匹配行的开头,前提是它后面跟着 ( (?=...)) 后跟任意数量的字符 ( .*) 后跟def并且它后面跟着任意数量的字符后跟jkl

grep该支持的实现-P比不过更多sed,因此:

grep -vP '^(?=.*def)(?=.*jkl)'

会更便携。

答案2

由于您声明 substring-match 也将构成删除标准,因此以下awk程序应该有效:

~$ awk '!(/def/ && /jkl/)' test.txt
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

这只会打印执行以下操作的行不是满足条件“行匹配defjkl”。

如果必须如此sed,你可以适应Stéphane Chazelas 的回答:

~$ sed -e '/def/!b' -e '/jkl/d' test.txt 
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

答案3

您也可以使用 perl 代替。在这种情况下,它的语法比以下更容易理解sed

$ perl -ne 'print unless /def/ && /jkl/' test2.txt 
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

或者

$ perl -ne '/def/ && /jkl/ || print' test2.txt 
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

甚至:

$ perl -ne '(/def/ && /jkl/) ? next : print' test2.txt 
1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

答案4

使用 Raku(以前称为 Perl_6)

raku -ne '.put  unless .grep: all(/def/ , /jkl/);'

或者

raku -ne '.put if .grep: { !/def/ || !/jkl/ };'

OR(Raku 相当于 @terdon 的 Perl5 代码):

raku -ne '.put unless /def/ && /jkl/;'

或者

raku -ne '/def/ && /jkl/ || .put;'

或者

raku -ne '(/def/ && /jkl/) ?? {next} !! .put'

输入示例:

1. abc def ghi
2. def ghi jkl
3. jkl mno pqr
4. jkl def stu
5. vwx yza bcd

示例输出:

1. abc def ghi
3. jkl mno pqr
5. vwx yza bcd

简而言之,前两个答案使用-ne(非自动打印)逐行标志以及 Raku 的grep例程。接下来的三个答案是 @terdon 的 Perl(5) 答案的 Raku 等效项。

前两行 ( grep) 代码很有趣,因为它们使用两种不同的机制:第一行使用连接all(通常在 Raku 中的集合上调用),而第二个示例在代码块grep上运行{},该代码块布尔化为 True/错误的。

前两个 ( grep) 结果的一个很好的变化是利用例程中可用的额外参数 ( :k, :v, :kv, :p) grep。例如,只需添加:p对(“状语”参数)即可指示代码将结果输出为编号对:

raku -ne '.put if .grep( { !/def/ || !/jkl/ }, :p );' 

示例输出(带索引):

0 => 1. abc def ghi
2 => 3. jkl mno pqr
4 => 5. vwx yza bcd

https://raku.org

相关内容