1

为什么这不起作用?

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不适用于参数扩展调试,我无法弄清楚。

GNU Bash 参考手册中解释它的链接也会有所帮助。

注意:Expected:中的$来自cat -A选项,代表换行符\n字符。

4

2 回答 2

1

为什么这不起作用?

显然是因为 Bash 在 ANSI-C 引用方面存在长期的行为不一致。

它的 ANSI-C 引用文档没有任何上下文异常。

它的 heredocs 文档没有做出任何似乎相关的特殊规定:

如果[分隔符]不加引号,则here-document的所有行都经过参数扩展、命令替换和算术扩展,字符序列\newline被忽略,必须使用'\'来引用字符'\', '$' 和 '`'。

因为我认为最后一句话暗示了“为了消除它们的特殊意义”,我在那里或在参数扩展的描述中看不到任何东西表明参数扩展在heredoc中的工作方式与在其他地方的工作方式不同。

但显然,确实如此。具体来说,ANSI-C 引用的字符串在 heredocs 之外的参数扩展中被识别,但在词汇表中与 heredocs 内的相同参数扩展不同。这似乎会影响所有形式的参数扩展,其中将参数名称以外的文本作为扩展的一部分,并且它不依赖于任何 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 中也不能直接识别单引号或双引号的引用,但是这些引用形式仍然可以在嵌入在 heredocs 中的参数扩展中识别。我很难理解为什么不应该将某些参数扩展在 heredocs 内部的解释与在外部解释不同的错误视为错误。

于 2022-02-25T23:19:35.927 回答
1

我认为您需要删除\参数扩展中的一些。

也就是说,它应该是${bla//$'\n'\$$'\n'}.

$ bla="
multi
line
string
"
$ printf "%q\n" "$bla"
$'\nmulti\nline\nstring\n'
$ gcat -A <<EOF
${bla//$'\n'/\$$'\n'}
EOF
$
multi$
line$
string$
$

$在每行的末尾添加了一个。

$ bla="
multi
line
string
"
$ printf "%q" "$bla"
$'\nmulti\nline\nstring\n'
$ 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
于 2022-02-25T17:45:05.463 回答