bash变量扩展$ {var:+" ..."}在这里 - 文档删除双引号?

时间:2016-12-06 12:32:38

标签: bash heredoc expansion quoting

我试图理解为什么Bash在使用function Calculate_Mean() { var str = document.getElementById("Num").value; var arr = str.split(","); // Will return array of string var count = arr.length; var sum=0; for (var i = 0; i < count; i++) { // You had 'int' instead of 'var' sum += parseInt(arr[i]); // Need to parse integer before adding } var mean = sum / count; return mean; } 使用备用值)进行变量扩展时删除双引号(但不是单引号),在here-document中,例如:

${parameter:+word}

根据手册,&#34;字&#34;在使用波形扩展,参数扩展,命令替换和算术扩展处理% var=1 % cat <<EOF > ${var:+"Hi there"} > ${var:+'Bye'} > EOF Hi there 'Bye' 之后。这些都不应该做任何事情。

我错过了什么?如何在扩展中获得双引号?

3 个答案:

答案 0 :(得分:13)

<强> TL;博士

$ var=1; cat <<EOF
"${var:+Hi there}"
${var:+$(printf %s '"Hi there"')}
EOF

"Hi there"
"Hi there"

上面演示了两个实用的解决方法,在备用值中包含双引号 嵌入式$(...)方法更麻烦,但更灵活:它允许包含嵌入式双引号,并且还可以控制是否应该扩展值。

Jens' helpful answerPatryk Obara's helpful answer都阐明并进一步证明了问题。

请注意,有问题的行为同样适用于

  • (如其他答案中所述)常规双引号字符串(例如echo "${var:+"Hi there"}";对于第1种解决方法,您必须\ - 引用"个实例;例如,echo "\"${var:+Hi there}\"";好奇地,Gunstick在问题评论中指出,在替代值中使用\" 在输出中生成" 在双引号字符串中工作 - 例如,echo "${var:+\"Hi th\"ere\"}" - 与未引用的here-docs不同。)

  • 相关扩展 ${var+...}${var-...} / ${var:-...}${var=...} / ${var:=...}

    < / LI>
  • 此外,对于\处理,在双引号字符串中的双引号替代值内部存在相关奇怪/未引用此处-doc:{{1并且bash意外地删除嵌入式ksh实例;例如,
    \意外地产生了echo "${nosuch:-"a\b"}",即使ab处于隔离状态echo "a\b" - 请参阅this question

我对行为 [1] 无解释 ,但我可以提供适用于所有主要POSIX兼容shell(<{1}},a\bdashbash)的实用解决方案:< / p>

请注意,替代值中的语法原因永远不需要 ksh个实例:替代值隐式处理为双引号string :没有波浪扩展,没有字拆分,也没有发生浮点数,但执行了参数扩展,算术扩展和命令替换

请注意,在涉及替换前缀/后缀删除的参数扩展中,引号 do 具有句法含义;例如: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'
    

可以根据需要组合这两种方法。

[1] 实际上,替代值:

  • 的行为类似于隐式双引号字符串
  • 与常规双引号字符串一样,
  • # 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 实例视为文字也是有意义的,只需将它们传递出来,就像'个实例一样。
    相反,遗憾的是,它们已被删除,如果您尝试将其"转义为'\"也会被保留(在此处未加引号内 - 文件,但奇怪的是不在双引号字符串中),除了 \ - 值得称赞的例外 - ksh实例 被删除。在 \ 中,奇怪的是,尝试使用 zsh完全打破了扩展(所有这些都是非平衡未转义弹)。

    • 更具体地说,双引号在替代值中没有没有语法功能,但它们解析它们就好像它们:应用了引用删除,你可以'在没有\"的内部使用(不平衡)"实例 - 转义它们(如上所述,这是无用的,因为保留了\"个实例)。

给定隐式双引号字符串语义,文字\实例必须是$ - 转义,或者必须使用命令替换来嵌入单引号字符串({{1} })。

答案 1 :(得分:4)

行为看起来是故意的 - 它在我尝试的所有Bourne shell中都是一致的(例如ksh93和zsh的行为方式相同)。

此行为等同于将here-doc视为仅用于这些特殊扩展的双引号。换句话说,你得到的结果与

相同
$ echo "${var:+"hi there"}"
hi there
$ echo "${var:+'Bye'}"
'Bye'

在POSIX规范中只有一个非常微弱的提示我发现参数扩展中的双引号字会发生特殊情况。这来自informative "Examples" section of Parameter Expansion

  

模式的双引号取决于双引号的放置位置。

     

"${x#*}"
         &lt;星号&gt;是一个模式人物      ${x#"*"}
         文字&lt;星号&gt;被引用而不是特别的。

我会读到最后一行,建议双引号的引用删除适用于该单词。这个例子对于单引号没有意义,并且由于省略,单引号没有引用删除。

<强>更新

我尝试了FreeBSD /bin/sh,它来自Almquist Shell。这个shell输出单引号和双引号。因此,所有 shell之间的行为不再一​​致,只是在我尝试过的大多数 shell之间。

至于在:+之后的单词扩展中得到双引号,我的看法是

$ var=1
$ q='"'
$ cat <<EOF
${var:+${q}hi there$q}
EOF
"hi there"

答案 2 :(得分:3)

$ cat <<EOF
${var:+bare alt value is string already}
${var:+'and these are quotes within string'}
${var:+"these are double quotes within string"}
${var:+"which are removed during substitution"}
"${var:+but you can simply not substitute them away ;)}"
EOF
bare alt value is string already
'and these are quotes within string'
these are double quotes within string
which are removed during substitution
"but you can simply not substitute them away ;)"

请注意,此处不需要文档来重现:

$ echo "${var:+'foo'}"
'foo'