字符串中的ANSI C引用是如何工作的



为什么不起作用?

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内部的解释与在外部的解释不同,这不应该被视为一个错误。

相关内容

  • 没有找到相关文章

最新更新