我试图理解为什么 Bash 在使用 ${parameter:+word}
进行变量扩展时删除双引号(而不是单引号) (使用替代值),在此处的文档中,例如:
% var=1
% cat <<EOF
> ${var:+"Hi there"}
> ${var:+'Bye'}
> EOF
Hi there
'Bye'
根据手册,
:+
后面的“词”用波浪号扩展、参数扩展、命令替换和算术扩展进行处理。这些都不应该做任何事情。我错过了什么?如何在扩展中获得双引号?
最佳答案
tl;博士
$ var=1; cat <<EOF
"${var:+Hi there}"
${var:+$(printf %s '"Hi there"')}
EOF
"Hi there"
"Hi there"
以上演示了两种实用的解决方法,以在替代值中包含双引号。
嵌入式
$(...)
方法更麻烦,但更灵活:它允许包含嵌入的双引号,还可以让您控制是否应该扩展值。Jens' helpful answer和 Patryk Obara's helpful answer两者都阐明并进一步证明了这个问题。
请注意 问题行为同样适用于 :
echo "${var:+"Hi there"}"
;对于第一个解决方法,您必须在 \
周围引用 "
实例;例如, echo "\"${var:+Hi there}\""
;奇怪的是,正如 Gunstick 在对该问题的评论中指出的那样,使用\"
在输出中产生 "
的替代值中确实适用于双引号字符串 - 例如, echo "${var:+\"Hi th\"ere\"}"
- 与未加引号的 here-docs 不同。) ${var+...}
, ${var-...}
/${var:-...}
, 和 ${var=...}
/${var:=...}
\
相关的奇怪之处-处理在双引号字符串内的双引号替代值/未引用的此处文档:bash
和 ksh
意外删除嵌入 \
实例;例如。,echo "${nosuch:-"a\b"}"
意外产生 ab
,即使 echo "a\b"
独立 yield a\b
- 见 this question . 我有 不解释对于行为[1]
,但我可以提供务实的解决方案适用于所有主要的 POSIX 兼容 shell (
dash
、 bash
、 ksh
、 zsh
):请注意
"
替代值中的语法原因从不需要实例:替代值被隐式处理为双引号字符串 : 没有波浪号扩展,没有分词,也没有通配符发生,但会执行参数扩展、算术扩展和命令替换。请注意,在涉及替换或前缀/后缀删除的参数扩展中,引号确实具有句法含义;例如:
echo "${BASH#*"bin"}"
或 echo "${BASH#*'bin'}"
- 奇怪的是,dash
但是不支持单引号。引用整个扩展 ,绕过了
"
的问题从替代值中删除:# Double quotes
$ var=1; cat <<EOF
"${var:+The closest * is far from $HOME}"
EOF
"The closest * is far from /Users/jdoe"
# Single quotes - but note that the alternative value is STILL EXPANDED,
# because of the overall context of the unquoted here-doc.
var=1; cat <<EOF
'${var:+The closest * is far from $HOME}'
EOF
'The closest * is far from /Users/jdoe'
使用嵌入式命令替换 (未引用,尽管它的行为就像被引用一样):
# Expanded value with embedded quotes.
var=1; cat <<EOF
${var:+$(printf %s "We got 3\" of snow at $HOME")}
EOF
We got 3" of snow at /Users/jdoe
# Literal value with embedded quotes.
var=1; cat <<EOF
${var:+$(printf %s 'We got 3" of snow at $HOME')}
EOF
We got 3" of snow at $HOME
这两种方法可以根据需要结合使用。
[1]
实际上,替代值:
'
实例,就像在常规双引号字符串中一样,被视为文字。 综上所述,
"
是有意义的实例也作为文字,并简单地传递它们,就像 '
一样实例。 相反,可悲的是,它们已被删除,如果您尝试将它们作为
\"
转义, \
也保留了 (在未引用的此处文档中,但奇怪的是不在双引号字符串中),除了在 中ksh
- 值得称赞的异常(exception) - ,其中\
实例被删除。在 zsh
,奇怪的是,试图使用 \"
完全打破扩张 (就像所有 shell 中的不平衡未转义的一样)。"
没有 \"
的内部实例- 转义它们(如前所述,这是无用的,因为 \
实例被保留)。 鉴于隐含的双引号字符串语义,文字
$
实例必须是 \$
-escaped,或者必须使用命令替换来嵌入单引号字符串 ( $(printf %s '...')
)。
关于bash 变量扩展 ${var : +"..."} in here-document removing double quotes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40995523/