替换 bash 中两个字符串之间的未知字符串

Replace unknow string between two strings in bash

我想替换两个字符串之间的未知字符串。

(1(...) 2(...) 3(...))

我使用:

sed -i "s/2(.*)/2(new)/g"

但我明白了。 (它需要最后一个')')

(1(hello) 2(new)

我想要:

(1(...) 2(new) 3(...))

有人可以帮助我吗?

编辑:

感谢回答者,我还有一个案例:

 "data_1": [...], "data_2": [...], "data_3": [...]

我想在' "data_2": [ '和 data_2

之后第一次出现的 ']' 之间插入一个字符串

尝试:

echo '(1(...) 2(...) 3(...))' | sed 's/2\((\.*)\)/2(new)/g'

您需要转义您正在使用的括号。匹配

更新:来自 Benjamin W 的评论

echo '(1(...) 2(TIM) 3(...))' | sed -E 's/2\([^)]*\)/2(new)/g'

我曾尝试寻找与 sed 进行非贪婪模式匹配的 hack 解决方案,但发现 perl 通常似乎更容易完成工作。

除非您有仅使用 sed 的特定限制,否则您可以:

echo "(1(...) 2(...) 3(...))" | perl -pe "s/2(.*?)/2(new)/g"

正则表达式中的唯一区别是 .* 之后的 ? 非贪婪修饰符,它匹配第一个 ).

命令行选项详细here. Reference for non-greedy modifier is here

sed 使用贪心匹配,因此 OP 的尝试 - 2(.*) - 将匹配第一个文字 2( 加上以 ) 结尾的最长字符串;考虑以下我们的比赛从第一个 2( 开始并运行到最后一个 ):

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2(.*)/2(new)/'
(1(...) 2(new) more stuff

要将匹配限制为第一个匹配 ) 有几种方法,一个想法是明确什么匹配和不匹配,考虑:

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/'
(1(...) 2(new) 3(...) 2(abc) 4(...)) more stuff

在这种情况下,我们使用 2([^)]*) 表示匹配 2( 后跟任意数量的非 ) ([^)]*) 字符).

为了匹配 2(...) 的所有非贪婪出现(其中 ... 表示任何非 ) 字符)我们可以添加 global 限定符sed 脚本的结尾,例如:

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/g'
(1(...) 2(new) 3(...) 2(new) 4(...)) more stuff

使用sed

$ sed 's/([^)]*/(new/2' input_file
(1(...) 2(new) 3(...))