【问题标题】:Why doesn't my condition (-not A -and (A -or B -or C)) work?为什么我的条件 (-not A -and (A -or B -or C)) 不起作用?
【发布时间】:2019-08-06 11:36:44
【问题描述】:

我写了 _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 * 安装包 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 应该启用包安装。


编辑:我想了解原因:

我关注PetSerAI 评论,然后,我像这样删除括号:

if (-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full"))) { }

这行得通,但我不明白为什么。我 found this explain 关于 PowerShell 中的括号:

Powershell 是一种经过解析和解释的语言。解释器将括号视为控制结构,调用站点不需要或不需要。

但是对于test-function("Hello")hello 是字符串而不是结构。

function Test-Function {
  Param(
    [string]
    $hello
  )

  "String: $hello"
}

Test-Function("Hello")
Test-Function "Hello"

【问题讨论】:

  • if (-not (_in "-packages") -and ((_in "+packages") -or (_in "+base") -or (_in "+full")))
  • @PetSerAl 谢谢!我使用了错误的语法...
  • 不要编写自己的-in 实现...
  • PowerShell 将裸序列 -packages 解释为参数名称,因此不会将其作为参数传递 - 用引号限定它:powershell .\scripts\win\install_zds.ps1 +packages '-packages'
  • @TheIncorrigible1 不是一回事

标签: powershell if-statement logical-operators


【解决方案1】:

表达式

-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_inbar 的函数_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' }
}

【讨论】:

    【解决方案2】:

    请注意,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
    

    【讨论】:

    • 我认为 AND 和 OR 具有相同的优先级实际上是正确的行为。
    猜你喜欢
    • 2015-06-15
    • 2017-01-11
    • 2011-06-13
    • 2021-11-28
    • 2019-04-12
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    相关资源
    最近更新 更多