PowerShell在双引号内插值时输出数组项

时间:2012-02-08 15:41:17

标签: powershell string-interpolation

我在PowerShell中发现了一些奇怪的行为,包括数组和双引号。如果我在数组中创建并打印第一个元素,例如:

$test = @('testing')
echo $test[0]

Output:
testing

一切正常。但如果我在它周围加上双引号:

echo "$test[0]"

Output:
testing[0]

仅评估了$ test变量,并且数组标记[0]被字面上视为字符串。简单的解决方法是避免在双引号中插入数组变量,或者首先将它们分配给另一个变量。但这是设计的行为吗?

3 个答案:

答案 0 :(得分:19)

因此,当您使用插值时,默认情况下它只插入toto中的下一个变量。所以当你这样做时:

"$test[0]"

它将$ test视为下一个变量,它意识到这是一个数组并且没有好的方法来显示数组,所以它决定它不能插值并只是将字符串显示为字符串。解决方案是明确告诉PowerShell要插入的位在何处开始以及停止的位置:

"$($test[0])"

请注意,这种行为是我使用格式化字符串而不是依赖插值的主要原因之一:

"{0}" -f $test[0]

答案 1 :(得分:9)

在这种情况下你必须这样做:

echo "$($test[0])"

另一种方法是使用字符串格式

echo "this is {0}" -f $test[0]

请注意,当您访问字符串中的属性时也会出现这种情况。与"$a.Foo"一样 - 应写为"$($a.Foo)"

答案 2 :(得分:3)

EBGreen's helpful answer包含有效的解决方案,但只有 PowerShell 字符串扩展的粗略解释(字符串插值)

  • 只有变量本身可以直接嵌入直接双引号字符串("..."(相比之下)单引号字符串('...')与许多其他语言一样,用于 literal 内容)。

    • 这适用于引用特定命名空间的常规变量和变量;例如: -
      "var contains: $var""Path: $env:PATH"

    • 如果变量名后面的第一个字符可能会被误认为是名称的一部分 - 特别是: - 使用{...}要消除歧义的变量名称;例如: -
      "${var}""${env:PATH}"

    • 使用$作为文字,您必须使用` ,PowerShell的转义字符转义它;例如: -
      "Variable `$var"

  • 变量名之后的任何字符 - 包括[.被视为字符串的 literal 部分,因此为了索引嵌入变量($var[0])或访问属性$var.Count),您需要{{1} 子表达式运算符(事实上,$(...)允许您嵌入整个语句);例如:

    • $(...)
    • "1st element: $($var[0])"
    • "Element count: $($var.Count)"
  • 字符串化(到字符串转换)应用于任何不是字符串的变量值/评估结果:

    • 警告:可以应用特定于文化的格式,PowerShell选择 不变文化,这与美国大致相符 - 英文日期和数字格式;也就是说,日期和数字将以类似美国的格式表示(例如,月份第一日期格式和"Today's date: $((Get-Date -DisplayHint Date | Out-String).Trim())"作为小数点)。
    • 本质上,.方法在任何生成的非字符串对象或集合上被称为(严格来说,它是.ToString(),它会覆盖.psobject.ToString() 1}}在某些情况下,特别是对于数组/集合和PS自定义对象)

      • 请注意,这是与您直接输出变量或表达式时相同的表示形式,而且许多类型具有 no 有意义的默认字符串表示形式 - 它们只是返回它们完整类型名称
        但是,您可以嵌入.ToString()以显式应用PowerShell的默认输出格式。
    • 有关字符串化的更全面的讨论,请参阅我的this answer

如前所述,使用 $(... | Out-String),字符串格式化运算符(-f替代,用于字符串插值,用于分隔文字部分来自变量部分的字符串:

<format-string> -f <arg>[, ...]
  • 请注意在LHS上使用'1st element: {0}; count: {1:x}' -f $var[0], $var.Count ,因为格式字符串(模板)本身就是文字。在这种情况下使用'...'是一个很好的习惯,既可以表示使用文字内容的意图,又可以嵌入'...'字符而无需转义。

  • 除了简单的位置占位符(第一个参数为$。第二个为{0},...),您可以选择多运行< strong>格式化对字符串转换的控制;在上面的示例中,{1}请求数字的十六进制表示 有关可用格式,请参阅x运算符所基于的.NET框架String.Format method的文档。

  • 陷阱:-f具有较高的precedence,因此请确保-f 中包含除简单索引或属性访问之外的RHS表达式;例如,(...)无法按预期工作,只会'{0:N2}' -f 1/3

  • 警告:字符串插值与'{0:N2}' -f (1/3)之间存在重要差异

    • -f内的扩展不同,"..."运算符 对文化敏感:

      • 因此,以下两个看似等效的语句 产生相同的结果:

        -f
      • 请注意,只有PS> [cultureinfo]::CurrentCulture='fr'; $n=1.2; "expanded: $n"; '-f: {0}' -f $n expanded: 1.2 -f: 1,2 格式的命令才会尊重法语(-f)小数点(fr)。
        再次,请参阅previously linked answer,全面了解PowerShell何时不具备文化敏感性。

    • ,内的扩展不同,"..."将数组字符串化为-f

      <type-name>[]
      • 请注意PS> $arr = 1, 2, 3; "`$arr: $arr"; '$arr: {0}' -f (, $arr) $arr: 1 2 3 $arr: System.Object[] 插值如何创建所有数组元素的字符串化的空格分隔列表,而"..." - 格式化仅打印数组的类型名称。
        (如上所述,-f内的$arr相当于:
        "..."并且通常不可见的助手类型(1, 2, 3).psobject.ToString()提供友好的表示。)

      • 另请注意[psobject]如何在帮助器数组中包装数组(, ...),以确保$arr将表达式视为单个操作数 ;默认情况下,数组的元素将被视为个别操作数。