![如果在第二个模式之前替换一个模式 - 将字符串保留在两者之间](https://linux22.com/image/110650/%E5%A6%82%E6%9E%9C%E5%9C%A8%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%89%8D%E6%9B%BF%E6%8D%A2%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%BC%8F%20-%20%E5%B0%86%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BF%9D%E7%95%99%E5%9C%A8%E4%B8%A4%E8%80%85%E4%B9%8B%E9%97%B4.png)
这是我的代码:
printf '%s' '{$aaa} \\{$bbb} \{$ccc} {$ddd' | sed -r -e 's/(^|[^\\])\{\$/\1\$\{/g' -e 's/\\\\\{\$/\\\\\$\{/g'
结果:
${aaa} \\${bbb} \{$ccc} ${ddd
结果正常,除了最后一个模式 ,{$ddd
不应该被替换,因为它不以右括号结尾}
。
我怎样才能用 sed 做到这一点?
另外,如果您知道如何合并两个实际表达式,也很受欢迎(对我来说不是那么重要)
编辑:请注意,括号也执行相同的操作,($foo)
以$(foo)
答案1
从第一个任务开始,仅对 close 执行更改{}
:
printf '%s' '{$aaa} \\{$bbb} \{$ccc} {$ddd' | sed 's/{$\([^}]*\)}/${\1}/g'
也就是说,从{$
up 到结束之后的所有内容}
都放入\(\)
,因此我们可以在替换字符串中将其反向引用为\1
。输出:
${aaa} \\${bbb} \${ccc} {$ddd
现在,关于反斜杠转义。您的解决方案适用于\{$aaa}
(不要触摸)和\\{$aaa}
(替换),但是呢\\\{$aaa}
?它将执行更改,这可能是不希望的。
所以我建议首先删除所有双反斜杠。例如,我们将它们替换为不能成为字符串一部分的字符组合,#1
并最终将其更改回来。这样我们就可以只关注单个反斜杠:
printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/#1/g;s/{$\([^}]*\)}/${\1}/g;s/#1/\\\\/g'
最后我们可以更改\{
为#2
并在最后将其替换回来以摆脱它:
printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/#1/g;s/\\{/#2/g;s/{$\([^}]*\)}/${\1}/g;s/#2/\\{/g;s/#1/\\\\/g'
结果:${aaa} \\${bbb} \{$ccc} \\\{$eee} {$ddd
这适用于任意数量的反斜杠。
但如果没有像#
你这样可以自由使用的角色呢?您可以使用换行符,因为换行符不能成为行的一部分。既然你似乎使用 GNU sed
,你可以这样做
printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/\n1/g;s/\\{/\n2/g;s/{$\([^}]*\)}/${\1}/g;s/\n2/\\{/g;s/\n1/\\\\/g'
如果这应该在 POSIX 上运行sed
,您需要一个解决方法
答案2
使用 POSIX,sed
您可以按如下方式完成任务:
sed -e '
# case for {$var}
s/ \(\(\\\\\)\{0,\}\){\$\([^ }]*\)}/ \1${\3}/g
s/^\(\(\\\\\)\{0,\}\){\$\([^ }]*\)}/\1${\3}/
# case for ($var)
s/ \(\(\\\\\)\{0,\}\)(\$\([^ )]*\))/ \1$(\3)/g
s/^\(\(\\\\\)\{0,\}\)(\$\([^ )]*\))/\1$(\3)/
' input_file
假设空格是文件中唯一的空白。当然,我们可以使用 TAB 来解决,并将其作为 OP 的练习。通过可用的扩展,GNU sed
我们可以进一步简化上述内容,但我想给出一个POSIX
解决方案以赋予其更大的适用性。