为什么我的条件 (-not A -and (A -or B -or C)) 不起作用?
Why doesn't my condition (-not A -and (A -or B -or C)) work?
我写了 _in 函数来检测我们是否必须安装软件包。参数 -packages
和 +packages
有效,但 +base
和 +full
无效,我该如何解决?
$scriptArgs=$args
function _in {
Param($find)
foreach ($i in $scriptArgs) {
if ($i -eq $find) {
return 1
}
}
return 0
}
# Install packages
if (-not (_in("-packages")) -and (_in("+packages") -or _in("+base") -or _in("+full"))) {
PrintInfo "* Installing packages"
}
这个有效:
PS> powershell .\scripts\win\install_zds.ps1 +packages
* Installing packages
PS> powershell .\scripts\win\install_zds.ps1 +packages -packages
-packages
禁用包安装,+packages
启用包安装。
这行不通:
PS> powershell .\scripts\win\install_zds.ps1 +base
PS> powershell .\scripts\win\install_zds.ps1 +full
+base
和 +full
应该启用软件包安装。
编辑: 我想了解原因:
我关注评论,然后,我删除括号如下:
if (-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full"))) { }
这行得通,但我不明白为什么。我 found this explain 关于 PowerShell 中的括号:
Powershell is a parsed and interpreted language. The interpreter see's parenthesis as a control structure and is not expected or required at the Call Site.
但是对于 test-function("Hello")
,hello
是字符串而不是结构。
function Test-Function {
Param(
[string]
$hello
)
"String: $hello"
}
Test-Function("Hello")
Test-Function "Hello"
表达式
-not (_in("-packages")) -and (_in("+packages") -or _in("+base") -or _in("+full"))
未按照您显然期望的方式进行评估。
PowerShell 函数(与方法调用不同)期望它们的参数是不带括号的空格分隔列表,即 _in("foo")
应该是 _in "foo"
。括号在语法上没有错误(_in("foo")
是一个有效的表达式),但 PowerShell 会将括号解析为分组表达式,首先对其求值。这意味着 PowerShell 在实际调用函数之前首先将 _in("foo")
扩展为 _in "foo"
。
但是,由于您将函数调用放在布尔表达式中,因此您需要在每个函数调用周围放置分组括号,以便首先计算函数调用,以便在布尔表达式中使用函数调用的结果:
(_in "foo") -and (_in "bar")
否则,布尔运算符将被解析为第一个函数的参数。也就是说
_in("foo") -and _in("bar")
将扩展为
_in "foo" -and _in "bar"
然后将使用参数 foo
、-and
、_in
和 bar
.
调用函数 _in()
因此你的条件必须写成
-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full"))
话虽如此,您尝试实现的不仅会重新实现 -in
/-contains
运算符,而且还违反了正常的 PowerShell 参数处理。我强烈建议您查看 advanced function parameters 和参数集。它们在函数和脚本级别上工作。
示例:
[CmdletBinding(DefaultParameterSetName='none')]
Param(
[Parameter(ParameterSetName='base', Mandatory=$true)]
[Switch]$Base,
[Parameter(ParameterSetName='full', Mandatory=$true)]
[Switch]$Full
)
switch ($PSCmdlet.ParameterSetName) {
'none' { 'install nothing' }
'base' { 'base install' }
'full' { 'full install' }
}
请注意,Powershell 在涉及 -and 和 -or 时非常不寻常,它们具有相同的优先级。大多数其他语言不是这样的(C#、vbscript...)。似乎一开始就被忽略了,现在他们不想破坏现有的脚本。
$true -or $true -and $false
False
$true -or ($true -and $false)
True
这是更典型的行为,带有 + 和 *。 * 比 + 具有更高的优先级。
1 + 2 * 3
7
(1 + 2) * 3
9
我写了 _in 函数来检测我们是否必须安装软件包。参数 -packages
和 +packages
有效,但 +base
和 +full
无效,我该如何解决?
$scriptArgs=$args
function _in {
Param($find)
foreach ($i in $scriptArgs) {
if ($i -eq $find) {
return 1
}
}
return 0
}
# Install packages
if (-not (_in("-packages")) -and (_in("+packages") -or _in("+base") -or _in("+full"))) {
PrintInfo "* Installing packages"
}
这个有效:
PS> powershell .\scripts\win\install_zds.ps1 +packages * Installing packages PS> powershell .\scripts\win\install_zds.ps1 +packages -packages
-packages
禁用包安装,+packages
启用包安装。
这行不通:
PS> powershell .\scripts\win\install_zds.ps1 +base PS> powershell .\scripts\win\install_zds.ps1 +full
+base
和 +full
应该启用软件包安装。
编辑: 我想了解原因:
我关注
if (-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full"))) { }
这行得通,但我不明白为什么。我 found this explain 关于 PowerShell 中的括号:
Powershell is a parsed and interpreted language. The interpreter see's parenthesis as a control structure and is not expected or required at the Call Site.
但是对于 test-function("Hello")
,hello
是字符串而不是结构。
function Test-Function {
Param(
[string]
$hello
)
"String: $hello"
}
Test-Function("Hello")
Test-Function "Hello"
表达式
-not (_in("-packages")) -and (_in("+packages") -or _in("+base") -or _in("+full"))
未按照您显然期望的方式进行评估。
PowerShell 函数(与方法调用不同)期望它们的参数是不带括号的空格分隔列表,即 _in("foo")
应该是 _in "foo"
。括号在语法上没有错误(_in("foo")
是一个有效的表达式),但 PowerShell 会将括号解析为分组表达式,首先对其求值。这意味着 PowerShell 在实际调用函数之前首先将 _in("foo")
扩展为 _in "foo"
。
但是,由于您将函数调用放在布尔表达式中,因此您需要在每个函数调用周围放置分组括号,以便首先计算函数调用,以便在布尔表达式中使用函数调用的结果:
(_in "foo") -and (_in "bar")
否则,布尔运算符将被解析为第一个函数的参数。也就是说
_in("foo") -and _in("bar")
将扩展为
_in "foo" -and _in "bar"
然后将使用参数 foo
、-and
、_in
和 bar
.
_in()
因此你的条件必须写成
-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full"))
话虽如此,您尝试实现的不仅会重新实现 -in
/-contains
运算符,而且还违反了正常的 PowerShell 参数处理。我强烈建议您查看 advanced function parameters 和参数集。它们在函数和脚本级别上工作。
示例:
[CmdletBinding(DefaultParameterSetName='none')]
Param(
[Parameter(ParameterSetName='base', Mandatory=$true)]
[Switch]$Base,
[Parameter(ParameterSetName='full', Mandatory=$true)]
[Switch]$Full
)
switch ($PSCmdlet.ParameterSetName) {
'none' { 'install nothing' }
'base' { 'base install' }
'full' { 'full install' }
}
请注意,Powershell 在涉及 -and 和 -or 时非常不寻常,它们具有相同的优先级。大多数其他语言不是这样的(C#、vbscript...)。似乎一开始就被忽略了,现在他们不想破坏现有的脚本。
$true -or $true -and $false
False
$true -or ($true -and $false)
True
这是更典型的行为,带有 + 和 *。 * 比 + 具有更高的优先级。
1 + 2 * 3
7
(1 + 2) * 3
9