我有一个计算的 PowerShell 变量,可以设置为 $True(布尔值)、“True”(字符串)、$False(布尔值)或“False”(字符串),我想测试它是否为“True” “(布尔值或字符串)。
虽然我可以轻松地构建成功的测试,如下所示:
$MyVar = $false
If (($MyVar -eq $True) -or ($MyVar -eq 'True')) {1} Else {0}
0
如果我将其更改为下面更简洁的格式,我会得到意想不到的结果:
If ($MyVar -in @($True,'True')) {1} Else {0}
1
任何人都可以解释为什么集合运算符 -in 和 -contains 会有这样的行为吗? 我在 PowerShell 5.1 和 PWSH 7.4.1 中观察到了这种行为
我尝试了多种变体,并且观察到了相同的意外行为。
If ('False' -in @($true)) {1} else {0}
1
If (@($true) -contains 'False') {1} else {0}
1
这篇 stackoverflow 文章:https://stackoverflow.com/questions/38002509/powershell-why-does-truth-contain-lies 说:“发生的情况是,它正在转换操作的右侧以匹配左侧的类型”;例如
$true -eq "Lies" ~> $true -eq [Bool]"Lies"
正确
但是当我在这里反转比较元素时,这似乎并没有发生:
If ('False' -in @($true)) {1} else {0}
1
tl;博士
为了避免下一节中描述的陷阱,请使用:
if ("$MyVar" -eq 'True') { 1 } Else { 0 }
也就是说,使用可扩展(插值)、双引号字符串("..."
)
对变量进行字符串化并执行字符串比较:
$MyVar
是 [bool]
实例,则它会字符串化为 'True'
或 'False'
无论当前区域性如何$MyVar
已经 is 为字符串,则 "..."
中的封装实际上是空操作。-eq
运算符默认情况下不区分大小写;如果您想要大小写精确匹配,请使用区分大小写的变体,-ceq
。
在 -in
-contains
操作中键入强制转换:'False' -in @($true)
相当于
@($true) -contains 'False'
。也就是说,所涉及的两个运算符 和
-contains
是等效的,不同之处仅在于哪个操作数是标量还是要测试包含性的集合。在两种
情况下,集合操作数的元素实际上充当针对每个集合元素与标量操作数执行的隐含-eq
比较的
LHS。 因此,以上两者都是有效
等价于:
@($true).Where({ $_ -eq 'False' }, 'First').Count -eq 1
鉴于通常是[1]
操作的LHS驱动PowerShell中的隐式类型强制,与-in
和
-contains
,因此是每个集合元素驱动类型强制。 使用
[bool]
实例作为 LHS,如本例所示,根据
about_Booleans中描述的规则将 RHS 强制为该类型。 这些规则特别包括将任何非空字符串视为
$true
,无论字符串的内容。 因此,
$true -eq 'False'
- 也许令人惊讶的是 -
$true
,因为 'False'
是一个 非空字符串。
-
和
/
总是将 both操作数解释为 numbers;例如,
'10' - '2'
产生 [int] 8
。原因是,对于这些特定的运算符,将 解释为数字是唯一合理的解释 - 与
+
和 *
等多态运算符不同。