如何在 sed 脚本中使用 sed 删除括号内的字符串?
Posted
技术标签:
【中文标题】如何在 sed 脚本中使用 sed 删除括号内的字符串?【英文标题】:How can I delete a string inside parentheses using sed, inside a sed script? 【发布时间】:2021-12-12 18:21:58 【问题描述】:我想在 sed 脚本中使用 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 运行它时,它确实有效,但由于某种原因在脚本中运行它时它不起作用。
【问题讨论】:
【参考方案1】:你可以使用
sed 's/ *([^()_]*)//g' file > outputfile
与 POSIX ERE 语法相同的模式:
sed -E 's/ *\([^()_]*\)//g' file > outputfile
详情:
*
(
- 文字 (
字符(因为它是 POSIX BRE 模式),当使用 POSIX ERE 时,必须使用 \(
[^()_]*
- 除了(
、)
和 _
之外的零个或多个字符
)
- 文字 )
字符(因为它是 POSIX BRE 模式),当使用 POSIX ERE 时,必须使用 \)
。
见online demo:
#!/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)
演示截图:
【讨论】:
嗯。当我运行这个命令时,它会删除我文件中的所有文本,只留下括号和下划线。不确定发生了什么? @JoshuaBorden 你没有使用我的代码。 我确实在使用确切的代码。你在说什么? @JoshuaBorden 如果您使用sed 's/ *([^()_]*)//g' file > outputfile
,outputfile
将具有预期的文本。
@JoshuaBorden 那么,它现在是否适用于 POSIX ERE 模式?您必须有-r
或-E
选项。【参考方案2】:
第一个解决方案(sed
解决方案): 使用您展示的示例,请尝试遵循sed
程序。在此处使用sed
的反向引用功能。
sed -E 's/(^[^(]*) \([^)]*\), \([^)]*\)(.*)/\1\2/' Input_file
解释:在这里使用sed
的-E
选项在我们的程序中启用ERE(扩展正则表达式)。然后在主程序中使用sed
的s
选项进行替换操作。我们提到了(^[^(]*) \([^)]*\), \([^)]*\)(.*)
,它在这里创建了 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
解决方案,使用awk
的match
函数。使用的正则表达式与上面提到的相同,因此对该程序的简单解释是;通过此功能匹配不需要的部分并仅打印需要的部分。
awk '
match($0,/[[:space:]]*\([^)]*\),[[:space:]]*\([^)]*\)/)
print substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
' Input_file
【讨论】:
很抱歉我忘了提这个!还有一个带有“-”的括号,就像这样“(Earth-16)”我也需要摆脱它。您的代码完美运行。有没有办法删除那个也有“-”的? @JoshuaBorden,肯定不是问题,请尝试以下代码:sed -E 's/(^[^(]*) \([^)]*\), \([^)]*\)(.*)/\1\2/' Input_file
一次,然后告诉我进展如何,干杯。【参考方案3】:
这可能对你有用(GNU sed):
sed -E ':a;s/ *\([^()]*\),(.*\(.*\))/\n\1/;ta;s/,*\n+/,/g' file
用换行符替换括号中的所有文字(包括括号),前面有一个可能的空格,后面是,
,后面至少还有一个括号内的文字。
然后用单个,
替换前面可能有,
的多个换行符。
【讨论】:
【参考方案4】:使用sed
$ sed 's/,\? ([^)][A-Za-z -]*)//g' input_file
Star Lord, age 42, actor, (Chris_Pratt)
【讨论】:
【参考方案5】:您应该澄清您是否真的在为“扩展”正则表达式使用-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)
(注意第一个逗号)。我相应地修复了解决方案。
【讨论】:
以上是关于如何在 sed 脚本中使用 sed 删除括号内的字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 shell 脚本中使用 sed 从文件的每一行中删除单词? [复制]
如何在bash脚本中使用Bash / Sed / Awk / Perl删除分隔字符串的最后一个元素[duplicate]