为什么不起作用?
bla="
multi
line
string
"
cat -A <<EOF
${bla//$'n'/\$'n'}
EOF
这项工作:
cat -A <<EOF
$(cat <<<${bla//$'n'/\$'n'})
EOF
正如评论中所指出的,这也起作用:
newline=$'n'
cat -A <<EOF
${bla//$newline/\$newline}
EOF
预期:
$
multi$
$
line$
$
string$
我想这与引用以及heredocs的工作方式有关。但由于set -x
不适用于参数扩展调试,我无法确定。
链接到GNUBash参考手册中的解释也会有所帮助。
注意:中的$预期:来自cat-选项,代表换行符\n。
我认为您需要在参数扩展中删除一些。
也就是说,它应该读${bla//$'n'$$'n'}
。
$ bla="
multi
line
string
"
$ printf "%qn" "$bla"
$'nmultinlinenstringn'
$ gcat -A <<EOF
${bla//$'n'/$$'n'}
EOF
$
multi$
line$
string$
$
我在每行的末尾添加了一个$
。
$ bla="
multi
line
string
"
$ printf "%q" "$bla"
$'nmultinlinenstringn'
$ printf "%s" "${bla//$'n'/$$'n'}"
$
multi$
line$
string$
$ printf "%q" "${bla//$'n'/$$'n'}"
$'$nmulti$nline$nstring$n'
我正在使用
$ echo $BASH_VERSION
5.1.16(1)-release
- 关于";此处文档">
- 参数扩展见第3.5.3节
- 参见第3.1.2.4节ANSI-C报价
为什么不起作用?
显然是因为Bash在ANSI-C引用方面存在长期的行为不一致。
它的ANSI-C引用文档没有任何上下文例外。
此处的文档没有做出任何相关的特殊规定:
如果[分隔符]未被引用,则here文档的所有行都将受到参数扩展、命令替换和算术扩展,字符序列
newline
被忽略,必须使用"\"引用字符"\"、"$"one_answers"`"。
因为我认为最后一句话有一个隐含的";为了去除它们的特殊意义";,我在这里或参数扩展的描述中没有看到任何内容表明参数扩展在heredoc中的工作方式与在其他地方的工作方式不同。
但很明显,确实如此。具体来说,ANSI-C引用的字符串在heredocs外部的参数展开中被识别,但在heredoc内部的词法上相同的参数展开不被识别。这似乎会影响所有形式的参数扩展,这些扩展包含参数名称以外的文本作为扩展的一部分,并且它不依赖于任何C样式转义序列的使用。示例:
$ ex1=abcdef
$ cat <<<${ex1#*$'b'}
cdef
$ cat <<EOF
${ex1#*$'b'}
EOF
abcdef
ex2=a$bcdef
$ cat <<<${ex2%$'b'*}
a$
$ cat <<EOF
${ex2%$'b'*}
${ex2/$'b'/X}
EOF
a
aXcdef
实际行为似乎是,引入C风格引号的$
被视为一个字面字符,但单引号是根据其作为引号字符的普通作用来解释的。最简单的解决方法似乎是将ANSI-C引用的文本分配给一个变量:
var=$'b'
$ cat <<EOF
${ex1/${var}/X}
EOF
aXcdef
我首先倾向于猜测,这种行为差异与ANSI-C引用在heredoc的正文中没有被直接识别有关。然而,单引号或双引号的引用都不能在heredocs中直接识别,但这些引用形式仍然可以在嵌入在heredocc中的参数展开中识别。我很难理解为什么一些参数扩展在heredocs内部的解释与在外部的解释不同,这不应该被视为一个错误。