你怎么能在一个双引号string中使用对象的属性?
我有以下代码:
$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;
当我尝试使用string执行命令中的某个属性时:
& "$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
,这是无效的。
我的解决方法是将其复制到一个新的variables。
如何直接在双引号string中访问对象的属性?
当你在一个双引号string中包含一个variables名时,它将被该variables的值replace:
$foo = 2 "$foo"
变
"2"
如果你不想要你用单引号:
$foo = 2 '$foo'
但是,如果要访问属性或在双引号string中使用variables的索引,则必须将该子expression式放在$()
:
$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只在这些情况下扩展variables,仅此而已。 为了强制评估更复杂的expression式,包括索引,属性甚至完整的计算,必须将这些expression式包含在子expression式运算符$( )
,这会导致内部expression式被计算并embedded到string中。
@Joey有正确的答案,但只是为了增加一点,为什么你需要用$()
强制进行评估:
您的示例代码包含一个含糊不清的地方,指出为什么PowerShell的制作者可能select将扩展限制为仅仅是variables引用,而不支持对属性的访问(另外:通过调用ToString()
方法完成string扩展对象,这可以解释一些“奇怪”的结果)。
你的例子包含在命令行的最后:
...\$LogFileName.ldf
如果默认扩展对象的属性,则上面的内容将parsing为
...\
由于$LogFileName
引用的对象不会有一个名为ldf
的属性, $null
(或一个空string)将被replace为该variables。
@Joey有一个很好的答案。 有更多的.NET外观与String.Format等价物的另一种方式,我更喜欢当访问对象的属性:
关于汽车的事情:
$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }
创build一个对象:
$car = New-Object -typename psobject -Property $properties
插入一个string:
"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
文档说明: Get-Help about_Quoting_Rules
涵盖了string插值,但从PSv5开始并不深入。
用 PowerShell的string扩展 ( 双引号string中的string插值,包括双引号string )中的实用摘要来补充Joey的有用答案 :
-
直接embedded到
"..."
string中时,只会识别$foo
,$global:foo
(或$script:foo
,…)和$env:PATH
(环境variables)等引用,也就是说,variables引用本身被扩展,而不pipe下面的内容如何。-
为了消除string中后续字符的variables名 , 请将其放在
{
和}
; 例如${foo}
。
如果variables名后跟一个:
,PowerShell会考虑$
和:
范围说明符之间的所有内容,通常会导致插值失败 ,这一点尤其重要。 例如"$HOME: where the heart is."
rest,但是"${HOME}: where the heart is."
按预期工作。
(或者,`
暴露::"$HOME`: where the heart is."
)。 -
把一个
$
或者一个"
作为一个字面值 ,用escape char。 ( 反引号 )作为前缀,例如:
"`$HOME's value: `"$HOME`""
-
-
对于其他任何事情,包括使用数组下标和访问对象variables的属性 ,必须将expression式包含在
$(...)
, 子expression式运算符 (例如,"PS version: $($PSVersionTable.PSVersion)"
或"1st el.: $($someArray[0])"
)- 使用
$(...)
甚至可以将整个命令行的输出embedded到双引号string中(例如"Today is $((Get-Date).ToString('d'))."
)。
- 使用
-
插值结果不一定与默认的输出格式相同 (例如,如果将variables/子expression式直接输出到控制台,例如涉及默认格式化程序,请参阅
Get-Help about_format.ps1xml
):-
集合 (包括数组)通过在元素的string表示之间放置一个空格来转换为string(默认情况下,可以通过设置
$OFS
来指定不同的分隔符)例如:"array: $(@(1, 2, 3))"
yieldarray: 1 2 3
-
如果实例types支持
IFormttable
接口[1] , 或者通过调用带有不变文化的IFormattable.ToString()
方法,则 任何其他types的实例(包括不是本身集合的集合的元素)都会被IFormattable.ToString()
化.psobject.ToString()
,在大多数情况下,它只是调用底层.NETtypes的.ToString()
方法 [2] ,它可能会或可能不会提供有意义的表示forms:除非(非原始types)types明确地覆盖了.ToString()
方法,所有你会得到的是完整的types名称 (例如,"hashtable: $(@{ key = 'value' })"
产生hashtable: System.Collections.Hashtable
)。 -
要获得与控制台相同的输出 ,使用子expression式和pipe道
Out-String
,如果需要,应用.Trim()
删除任何前导和尾随的空行。 例如,
"hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"
产生:hashtable: Name Value ---- ----- key value
-
[1]这也许令人惊讶的行为意味着,对于支持文化敏感表示的types, $obj.ToString()
产生一个当前的文化适当的表示,而"$obj"
(string内插)总是导致文化不变代表 – 看到我的这个答案 。
[2]值得注意的例外:
string展开[pscustomobject]
通过.psobject.ToString()
( 在这里解释)产生一个类似于散列表的表示,而调用.ToString()
直接产生空string 。