Como discutido nos comentários, isso parece ter mudado entre as versões do Bash. Penso que esta é a mudança relevante em bash-4.3-alpha
( changelog ):
zz. When using the pattern substitution word expansion, bash now runs the replacement string through quote removal, since it allows quotes in that string to act as escape characters. This is not backwards compatible, so it can be disabled by setting the bash compatibility mode to 4.2.
E a descrição para shopt -s compat42
( manual online ) :
compat42
If set, bash does not process the replacement string in the pattern substitution word expansion using quote removal.
O exemplo de aspas simples:
$ 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)
Solução: coloque a cadeia de substituição em uma variável, e não uso aspas dentro da substituição:
$ shopt -s compat42
$ qq="'\''"; s=abc\'def; echo "'${s//\'/$qq}'";
'abc'\''def'
$ qq="'\''"; s=abc\'def; echo "'${s//\'/"$qq"}'";
'abc"'\''"def'
O engraçado é que, se a expansão é unquoted , em seguida, as aspas são removidas após a substituição, em todas as versões. Isso é s=abc; echo ${s/b/""}
imprime ac
. Isto obviamente não acontece com outras expansões, e. s='a""c' ; echo ${s%x}
outputs a""c
.