如何在sed脚本中使用sed删除括号内的字符串?

3
我希望能够使用sed脚本来删除括号内的文本(包括括号)。例如,我想要删除短语(Chris Pratt)和(Chris-Pratt),但保留(Chris_Pratt)。它们都在同一行上。并且对整个文件执行此操作。例如,该行看起来像这样:
Star Lord (Chris Pratt), (Chris-Pratt), age 42, actor, (Chris_Pratt)

这是我希望在sed脚本中经过sed命令处理后的样子:
Star Lord, age 42, actor, (Chris_Pratt)

这就是我想要对每一行(还有其他名称的多个行)做的事情。

我已经尝试过:

s/[(][^)]*[)]//g

这个可以工作,但它也会删除括号和下划线,包括其中的标记
s/\([[:alpha:]]{1,} [[:alpha:] ]{1,}\)\ //g

这个命令行中使用sed时能够正常工作,但在脚本中却无法正常工作。
4个回答

1

您可以使用

sed 's/ *([^()_]*)//g' file > outputfile

与POSIX ERE语法相同的模式:

sed -E 's/ *\([^()_]*\)//g' file > outputfile

详情:

  • *
  • ( - 字面意义上的字符( (因为它是 POSIX BRE 模式),使用 POSIX ERE 时,必须使用 \(
  • [^()_]* - 零个或多个字符(除了()_
  • ) - 字面意义上的字符) (因为它是 POSIX BRE 模式),使用 POSIX ERE 时,必须使用 \)

查看 在线演示:

#!/bin/bash
s='Star Lord (Chris Pratt), age 42, actor, (Chris_Pratt)'
sed 's/ *([^()_]*)//g' <<< "$s"
# => Star Lord, age 42, actor, (Chris_Pratt)
sed -E 's/ *\([^()_]*\)//g' <<< "$s"
# => Star Lord, age 42, actor, (Chris_Pratt)

演示截图:

enter image description here


嗯,当我运行这个命令时,它会删除文件中的所有文本,只留下括号和下划线。不确定发生了什么? - Joshua Borden
@JoshuaBorden 你没有使用我的代码。 - Wiktor Stribiżew
我确实在使用完全相同的代码。你在说什么? - Joshua Borden
1
如果您使用 sed 's/ *([^()_]*)//g' file > outputfile,则 outputfile 将包含预期的文本。 - Wiktor Stribiżew
@JoshuaBorden,现在它是否与POSIX ERE模式兼容?您必须使用-r-E选项。 - Wiktor Stribiżew

0

第一种解决方案(sed 解决方案): 根据您提供的示例,请尝试以下 sed 程序。在此处使用 sed 的反向引用功能。

sed -E 's/(^[^(]*) \([^)]*\), \([^)]*\)(.*)/\1\2/' Input_file

解释:在我们的程序中使用sed-E选项,启用ERE(扩展正则表达式)。然后在主程序中使用seds选项执行替换操作。我们提到了(^[^(]*) \([^)]*\), \([^)]*\)(.*),这里创建了2个反向引用(在程序中检索捕获值的临时空间)。在替换时使用\1(第一个反向引用)和\2(第二个反向引用)来获取OP所述的预期输出。

正则表达式的解释:

(^[^(]*)               ##Creating 1st capturing group which captures values from starting of line to till 1st occurrence of ( here.
 \([^)]*\), \([^)]*\)  ##Matching space ( till next occurrence of ) here followed by comma then space followed by ( till next occurrence of ).
(.*)                   ##Creating 2nd capturing group which has everything after previous match.


第二种解决方案(awk 解决方案): 在这里添加了一个 awk 解决方案,通过使用 awkmatch 函数。所使用的正则表达式与上述相同,因此对于这个程序的简单解释是:通过这个函数匹配不需要的部分并只打印所需的部分。

awk '
match($0,/[[:space:]]*\([^)]*\),[[:space:]]*\([^)]*\)/){
  print substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
}
' Input_file

非常抱歉,我忘了提到这一点!还有一个带有"-"的括号,像这样"(Earth-16)",我也需要把它去掉。你的代码完美地运行了。有没有办法也去掉带有"-"的那个? - Joshua Borden
@JoshuaBorden,没问题,请尝试以下代码:sed -E 's/(^[^(]*) \([^)]*\), \([^)]*\)(.*)/\1\2/' Input_file,然后告诉我它的运行情况,谢谢。 - RavinderSingh13

0
这可能适用于您(GNU sed):
sed -E ':a;s/ *\([^()]*\),(.*\(.*\))/\n\1/;ta;s/,*\n+/,/g' file

将括号内(包括括号)可能有空格的文字替换为换行符,该文字后跟一个,,然后至少再有一个在括号内的文字。

然后将可能有,的多个换行符替换为单个,


0

你应该澄清一下是否实际使用了“扩展”正则表达式-E选项。

开启-E后,括号(())必须被转义(\()以匹配文字。如果不进行转义,则会被解释为组/字段分隔符(没有-E时则相反)。

我的解决方案假设-E已经开启。

  • 对于可执行的sed脚本,你的shebang应该类似于#!/bin/sed -Ef#!/usr/bin/env -Ssed -Ef

  • 对于非可执行的sed脚本,请像这样调用:sed -Ef my-script

解决方案:

如果所有行的布局都相同,请使用以下方法:

s/([[:space:]]+\([^)]+\),){2}/,/

如果布局不同,请尝试以下之一:
s/[[:space:]]*\([^)]*[- ][^)]+\)//
s/[[:space:]]*\([^)]*[- ][^)]+\),?//g

所有包含空格和/或破折号的括号字段都将被删除,同时还会删除前导空格和尾随逗号(如果存在)。仅对第一个匹配项保留任何逗号。

s/[[:space:]]*\([^)_]+\)//
s/[[:space:]]*\([^)_]+\),?//g

所有不包含下划线的括号字段都将被删除(包括(Madonna))。空格和逗号也是如此。

编辑:我稍微误读了您期望的输出。您将得到Star Lord age 42, actor, (Chris_Pratt)而不是Star Lord,age 42,actor,(Chris_Pratt)(注意第一个逗号)。我已相应地修正了解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接