如何在双引号字符串中使用对象的属性?

时间:2009-07-17 21:11:45

标签: powershell string-interpolation

我有以下代码:

$DatabaseSettings = @();
$NewDatabaseSetting = "" | select DatabaseName, DataFile, LogFile, LiveBackupPath;
$NewDatabaseSetting.DatabaseName = "LiveEmployees_PD";
$NewDatabaseSetting.DataFile = "LiveEmployees_PD_Data";
$NewDatabaseSetting.LogFile = "LiveEmployees_PD_Log";
$NewDatabaseSetting.LiveBackupPath = '\\LiveServer\LiveEmployeesBackups';
$DatabaseSettings += $NewDatabaseSetting;

当我尝试使用字符串执行命令中的一个属性时:

& "$SQlBackupExePath\SQLBackupC.exe" -I $InstanceName -SQL `
  "RESTORE DATABASE $DatabaseSettings[0].DatabaseName FROM DISK = '$tempPath\$LatestFullBackupFile' WITH NORECOVERY, REPLACE, MOVE '$DataFileName' TO '$DataFilegroupFolder\$DataFileName.mdf', MOVE '$LogFileName' TO '$LogFilegroupFolder\$LogFileName.ldf'"

它尝试仅使用$DatabaseSettings的值,而不是$DatabaseSettings[0].DatabaseName的值,这是无效的。
我的解决方法是将其复制到一个新变量中。

如何直接在双引号字符串中访问对象的属性?

4 个答案:

答案 0 :(得分:132)

当您在双引号字符串中包含变量名称时,它将被该变量的值替换:

$foo = 2
"$foo"

变为

"2"

如果您不希望必须使用单引号:

$foo = 2
'$foo'

但是,如果要访问属性,或者对双引号字符串中的变量使用索引,则必须将该子表达式括在$()中:

$foo = 1,2,3
"$foo[1]"     # yields "1 2 3[1]"
"$($foo[1])"  # yields "2"

$bar = "abc"
"$bar.Length"    # yields "abc.Length"
"$($bar.Length)" # yields "3"

Powershell仅在这些情况下扩展变量,仅此而已。要强制评估更复杂的表达式,包括索引,属性甚至完整的计算,您必须将它们包含在子表达式运算符$( )中,这会导致内部表达式被计算并嵌入到字符串中。

答案 1 :(得分:12)

@Joey有正确的答案,但只是为了补充一点,为什么你需要用$()强制进行评估:

您的示例代码包含一个歧义,指出PowerShell的制造商可能选择将扩展限制为仅仅是变量引用而不支持对属性的访问(旁白:字符串扩展是通过调用{{1对象的方法,可以解释一些“奇怪的”结果)。

您的示例包含在命令行的最后:

ToString()

如果默认情况下展开了对象的属性,则上述内容将解析为

...\$LogFileName.ldf

由于...\ 引用的对象没有名为$LogFileName的属性,ldf(或空字符串)将替换该变量。

答案 2 :(得分:8)

@Joey有一个很好的答案。还有另一种方法是使用String.Format等效的更多.NET外观,在访问对象的属性时我更喜欢它:

关于汽车的事情:

$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }

创建一个对象:

$car = New-Object -typename psobject -Property $properties

插入字符串:

"The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package

输出:

# The red car is a nice sedan that is fully loaded

答案 3 :(得分:6)

文档说明:Get-Help about_Quoting_Rules涵盖了字符串插值,但是,从PSv5开始,不是深入的。

使用PowerShell的 字符串扩展 实用摘要来补充Joey's helpful answer双引号中的字符串插值< / em>字符串,包括双引号here-strings):

  • 只有 $foo$global:foo(或$script:foo,...)和$env:PATH (环境变量)等参考文献当直接嵌入"..."字符串时被识别 - 也就是说,只有变量引用本身被扩展,而不管后面是什么。

    • 消除字符串中后续字符的变量名将其括在{} ;例如, ${foo} 如果变量名后跟:,这一点尤其重要,因为PowerShell会考虑$: 范围说明符之间的所有内容导致插值失败;例如,"$HOME: where the heart is."休息,但"${HOME}: where the heart is."按预期工作 (或者,` - 逃避:"$HOME`: where the heart is.")。

    • 要将$"视为文字,请在其前面添加转义字符。 ` 反引号);例如: -
      "`$HOME's value: `"$HOME`""

  • 对于其他任何事情,包括使用数组下标并访问对象变量的属性,您必须将表达式括在$(...) < / strong>,子表达式运算符(例如,"PS version: $($PSVersionTable.PSVersion)""1st el.: $($someArray[0])"

    • 使用$(...)甚至允许您将整个命令行的输出嵌入双引号字符串中(例如"Today is $((Get-Date).ToString('d')).")。
  • 插值结果不一定与默认输出格式相同(例如,如果将变量/子表达式直接打印到控制台,则会看到,默认格式化程序;请参阅Get-Help about_format.ps1xml):

    • 集合(包括数组)通过在元素的字符串表示之间放置单个空格来转换为字符串(通过默认;可以通过设置 $OFS 来指定其他分隔符。例如,"array: $(@(1, 2, 3))"会产生array: 1 2 3

    • 任何其他类型的实例(包括不是自身集合的集合元素) 字符串调用{{3}使用不变文化的方法,如果实例的类型支持IFormattable接口 [1] ,则调用{{1在大多数情况下,它只是调用基础.NET类型的.psobject.ToString()方法 [2] ,这可能会也可能不会给出有意义的表示:除非a(非原语)类型已经专门覆盖了.ToString()方法,您将获得完整的类型名称(例如,.ToString()产生"hashtable: $(@{ key = 'value' })")。

    • 获取与控制台中相同的输出,请使用子表达式和管道到hashtable: System.Collections.Hashtable 并应用Out-String删除任何前导和尾随空行,如果需要;例如,
      .Trim()收益:

      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"

[1]这可能令人惊讶的行为意味着,对于支持文化敏感表示的类型,hashtable: Name Value ---- ----- key value 会产生当前 - 文化适当的表示,而{{1 (字符串插值)总是会产生 culture-invariant 表示 - 请参阅我的IFormattable.ToString()

[2]值得注意的覆盖:
*之前讨论的集合的字符串化(以空格分隔的元素列表,而不是$obj.ToString())。
* hashtable- 类似表示"$obj"个实例(解释this answer)而不是空字符串