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

cav*_*ick 84 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;
Run Code Online (Sandbox Code Playgroud)

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

& "$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'"
Run Code Online (Sandbox Code Playgroud)

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

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

Joe*_*oey 143

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

$foo = 2
"$foo"
Run Code Online (Sandbox Code Playgroud)

"2"
Run Code Online (Sandbox Code Playgroud)

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

$foo = 2
'$foo'
Run Code Online (Sandbox Code Playgroud)

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

$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"
Run Code Online (Sandbox Code Playgroud)

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

  • @ ozzy432836当然可以.或者使用格式字符串.它通常并不重要,归结为个人偏好. (2认同)

Ste*_*ski 14

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

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

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

...\$LogFileName.ldf
Run Code Online (Sandbox Code Playgroud)

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

...\
Run Code Online (Sandbox Code Playgroud)

因为引用的对象$LogFileName没有被调用的属性ldf,所以$null(或空字符串)将替换该变量.


loo*_*101 9

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

关于汽车的事情:

$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }
Run Code Online (Sandbox Code Playgroud)

创建一个对象:

$car = New-Object -typename psobject -Property $properties
Run Code Online (Sandbox Code Playgroud)

插值字符串:

"The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package
Run Code Online (Sandbox Code Playgroud)

输出:

# The red car is a nice sedan that is fully loaded
Run Code Online (Sandbox Code Playgroud)

  • 当你第一次使用格式字符串时,需要注意的是,你经常需要将表达式括在parens中.你不能,比如简单地写`write-host`foo = {0}"-f $ foo`,因为PowerShell会将`-f`视为`write-host`的`ForegroundColor`参数.在这个例子中,你需要`write-host("foo = {0}" - f $ foo)`.这是标准的PowerShell行为,但值得注意. (3认同)

小智 7

如果您想使用引号内的属性,请按照以下步骤操作。您必须在括号外使用 $ 来打印属性。

$($variable.property)
Run Code Online (Sandbox Code Playgroud)

例子:

$uninstall= Get-WmiObject -ClassName Win32_Product |
    Where-Object {$_.Name -like "Google Chrome"
Run Code Online (Sandbox Code Playgroud)

输出:

IdentifyingNumber : {57CF5E58-9311-303D-9241-8CB73E340963}
Name              : Google Chrome
Vendor            : Google LLC
Version           : 95.0.4638.54
Caption           : Google Chrome
Run Code Online (Sandbox Code Playgroud)

如果您只想要名称属性,请执行以下操作:

"$($uninstall.name) Found and triggered uninstall"
Run Code Online (Sandbox Code Playgroud)

输出:

Google Chrome Found and triggered uninstall
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 6

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

为了补充乔伊的有用的答案有一个务实的总结 PowerShell的的字符串扩张(串插在双引号的字符串,包括双引号这里弦):

  • 只有这样作为参考"..."),$foo(或$global:foo,...)和$script:foo时(环境变量)被认为直接嵌入$env:PATH也就是说,只有变量引用-串本身展开,不论什么如下.

    • 要从字符串中的后续字符中消除变量名的歧义,请将其括在"..."和中{ ; 例如,}.
      如果变量名后面跟着,这一点尤其重要${foo},因为PowerShell中原本考虑之间的一切:$一个范围说明符,通常导致插值失败 ; 例如,:休息,但"$HOME: where the heart is."按预期工作.
      (可替换地,"${HOME}: where the heart is."-escape的`::).

    • 要将a "$HOME`: where the heart is."或a $视为文字,请使用escape char"作为前缀.(反击); 例如:
      `

  • 对于其他任何事情,包括使用数组下标和访问对象变量的属性,必须将表达式括"`$HOME's value: `"$HOME`""子表达式运算符中(例如,$(...)"PS version: $($PSVersionTable.PSVersion)")

    • 使用"1st el.: $($someArray[0])"even允许您将整个命令行的输出嵌入双引号字符串中(例如,$(...)).
  • 插值结果不一定与默认输出格式相同(例如,如果将变量/子表达式直接打印到控制台,则会看到,这涉及默认格式化程序;请参阅参考资料"Today is $((Get-Date).ToString('d'))."):

    • 通过在元素的字符串表示之间放置一个空格(默认情况下,可以通过设置指定不同的分隔符Get-Help about_format.ps1xml)集合(包括数组)转换为字符串.例如,$OFSyield"array: $(@(1, 2, 3))"

    • 的实例任何其他类型的(包括不是自身的集合的集合的元素)由字符串化或者调用array: 1 2 3该方法不变培养中,如果实例的类型支持IFormattable.ToString()接口[1] ,通过调用IFormattable,这在大多数情况下,只是调用底层的.NET类型的.psobject.ToString()方法[2],可能会或可能不会给出有意义的表示:除非(非原始)类型专门覆盖了该.ToString()方法,否则您将获得完整的类型名称(例如,.ToString()yield "hashtable: $(@{ key = 'value' })").

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

      hashtable:                                                                                                                                                                          
      Name                           Value                                                                                                                                               
      ----                           -----                                                                                                                                               
      key                            value      
      
      Run Code Online (Sandbox Code Playgroud)

[1]这可能令人惊讶的行为意味着,对于支持文化敏感表征的类型,"hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"产生当前文化适当的表示,而$obj.ToString()(字符串插值)总是导致文化不变表示 - 请参阅我的这个答案.

[2]值得注意的覆盖:
*前面讨论过的集合的字符串化(以空格分隔的元素列表而不是类似的东西"$obj").
*本hashtable- 喜欢的代表性System.Object[]实例(解释这里),而不是空字符串.

  • @AbrahamZinala,我不知道。也许变量引用带有消除歧义的名称通过大括号封闭?(只是在开玩笑。) (3认同)