Bash 如何处理参数扩展的字符串替换部分中的引用?

Wil*_*ard 7 bash quoting variable-substitution

它有什么一致的逻辑吗?

some-command "${somevariable//some pattern/'how does this get parsed?'}"
Run Code Online (Sandbox Code Playgroud)

我在下面发布了一些结论和原始测试作为“答案”,但无论如何它们都不是完整的答案。Bash 手册页似乎没有提及该主题。

ilk*_*chu 7

正如评论中所讨论的,这似乎在 Bash 版本之间发生了变化。我认为这是bash-4.3-alpha更改日志)中的相关更改:

Z Z。当使用模式替换词扩展时,bash 现在通过引号删除来运行替换字符串,因为它允许该字符串中的引号充当转义字符。这不是向后兼容的,因此可以通过将 bash 兼容模式设置为 4.2 来禁用它。

以及shopt -s compat42在线手册)的描述:

compat42
如果设置,bash 不会使用引号删除处理模式替换字扩展中的替换字符串。

引用单引号示例:

$ s=abc\'def; echo "'${s//\'/\'\\\'\'}'"
'abc'\''def'

$ shopt -s compat42
$ s=abc\'def; echo "'${s//\'/\'\\\'\'}'"
'abc\'\\'\'def'

$ bash --version | head -1
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)

解决方法:将替换字符串放在变量中,并且不要在替换中使用引号:

$ shopt -s compat42
$ qq="'\''"; s=abc\'def; echo "'${s//\'/$qq}'";
'abc'\''def'
$ qq="'\''"; s=abc\'def; echo "'${s//\'/"$qq"}'";
'abc"'\''"def'
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果扩展是unquoted,那么在所有版本中,替换后引号都会被删除。那是s=abc; echo ${s/b/""}印记ac。这当然不会发生在其他扩展中,例如s='a""c' ; echo ${s%x}输出a""c