Quoted parameter expansion with quoted modifier in Bash

时间:2016-06-10 16:17:00

标签: bash

I've noticed something weird:

Y=""
echo ${Y:-"\n"}
echo "${Y:-"\n"}"

prints

\n
n

Why is the second line n, not \n? Is this a bug?

It looks as if Bash parsed this as a concatenation of two quoted strings with an unquoted string in between ("${Y:-" and \n and "}") but this doesn't seem to be the case since the commands

echo $(echo "\n")
echo "$(echo "\n")"
echo "${Y:-"'\n'"}"

output

\n
\n
'n'

I'm using GNU bash, version 4.3.11.

3 个答案:

答案 0 :(得分:3)

我怀疑在处理:-之后的单词时存在一个错误(事实上,我似乎记得读过一些关于此的内容,但我记不起来了。)

如果没有引用该值,我会得到我期望的结果......

$ echo ${Y:-\n}
n
$ echo "${Y:-\n}"
\n

这也是您在dash中得到的结果(忽略dash实际生成文字换行的事实,因为POSIX要求echo处理转义字符,bash只有在使用非标准-e选项时才会这样做。)

在此示例中,引用默认值会保留反斜杠。由于参数扩展产生反斜杠,引用删除将其删除。

$ echo ${Y:-"\n"}   # Equivalent to echo "\n", so the output makes sense
\n

似乎没有任何理由让bash在最后一个例子中表现不同只是因为引用了整个参数扩展。这几乎就像引用删除被应用两次,一次删除外部双引号并再次错误地删除反斜杠。

# Quote removal discards the backslash: OK
$ echo \n
n
# Quote removal discards the double quotes: OK
$ echo "n"
n
# Quote removal discards the first backslash after `\\` is recognized
# as a quoted backslash: OK
$ echo \\n
\n 
# Quote removal discards the double quotes, but leaves
# backslash: OK
$ echo "\n"
\n
# Is quote removal discarding both the double quotes *and* the backslash? Not OK
$ echo "${Y:-"\n"}"
n

相关,zshbsd_echo)选项设置输出\n,而不是n

% Y=""
% echo "${Y:-"\n"}"
\n

答案 1 :(得分:2)

补充chepner's helpful answer

这里概述了类似POSIX的主要shell如何处理以下命令:

Y=""
printf '%s\n' ${Y:-"\n"} ${Y:-'\n'} "${Y:-"\n"}" "${Y:-'\n'}"

请注意,我已使用单个引号添加了变体。

dash                                    [v0.5.8]
  \n
  \n
  \n
  '\n'

zsh                                     [v5.0.8]
  \n
  \n
  \n
  '\n'

bash                                   [v4.3.42]
  \n
  \n
  n
  '\n'

ksh                                     [93u+]
  \n
  \n
  n
  '\n'
  • 奇怪的是,在所有 shell中,'\n' 中的"..."会保留单引号,同时在中删除它们未加引号的案例。

  • 对于"\n"bashksh都表现出OP发现的奇怪现象,而dashzsh则没有。

答案 2 :(得分:0)

也许我看错了,但我没有看到任务中的任何不一致,默认值为Y引用未加引号。每种情况下的echo表达式归结为:

$ echo "\n"
\n

$ echo ""\n""
n

在第一种情况下,你有引用的字符串"\n",在第二种情况下,你有一个\n(只是n