如果在第二个模式之前替换一个模式 - 将字符串保留在两者之间

如果在第二个模式之前替换一个模式 - 将字符串保留在两者之间

这是我的代码:

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解决方案以赋予其更大的适用性。

相关内容