【问题标题】:conditional execution (&& and ||) in powershellpowershell 中的条件执行(&& 和 ||)
【发布时间】:2010-02-12 12:05:46
【问题描述】:

已经有问题解决了我的问题 (Can I get && to work in Powershell?),但有一点不同。我需要两个命令的 OUTPUT。看,如果我只是运行:

(command1 -arg1 -arg2) -and (command2 -arg1)

我不会看到任何输出,但会看到 stderr 消息。而且,正如预期的那样,只需输入:

command1 -arg1 -arg2 -and command2 -arg1 

给出语法错误。

【问题讨论】:

  • 只有当第一个 eval 为 false(失败)时,短路 OR 才会执行第二个表达式。我怀疑 OP 希望第二个表达式只有在第一个 eval 为真(成功)的情况下才执行,这是一个短路 - 并给了我们。
  • 任何对 Bash 风格的 &&|| 成为 PowerShell 的一部分感兴趣的人:请为 here 的功能投票。
  • 注意:尽管这个问题的磁贴同时提到了&&||,但正文——以及随后的答案——只关注&&closely related question 更通用。
  • 2019 年 6 月更新:PowerShell 团队正在实施 &&||!在GitHub PR称重

标签: syntax powershell command-execution


【解决方案1】:

2019:Powershell 团队是considering adding support for && to Powershell - weigh in at this GitHub PR

试试这个:

$(command -arg1 -arg2 | Out-Host;$?) -and $(command2 -arg1 | Out-Host;$?)

$() 是一个子表达式,允许您在包括管道的情况下指定多个语句。然后执行命令和管道到Out-Host,这样你就可以看到它了。下一条语句(子表达式的实际输出)应输出$?,即最后一条命令的成功结果。


$? 适用于本机命令(控制台 exe),但对于 cmdlet,它还有一些不足之处。也就是说,$? 似乎只在 cmdlet 遇到终止错误时返回 $false。似乎$? 至少需要三种状态(失败、成功和部分成功)。因此,如果您使用 cmdlet,这会更好:

$(command -arg1 -arg2 -ev err | Out-Host;!$err) -and 
$(command -arg1 -ev err | Out-Host;!$err)

这种打击还在。也许这样的事情会更好:

function ExecuteUntilError([scriptblock[]]$Scriptblock)
{
    foreach ($sb in $scriptblock)
    {
        $prevErr = $error[0]
        . $sb
        if ($error[0] -ne $prevErr) { break }
    }
}

ExecuteUntilError {command -arg1 -arg2},{command2-arg1}

【讨论】:

  • 谢谢,Keith(顺便说一句,我使用 PSCX 并发现它很棒,非常感谢!)。虽然它看起来很实用,但与 UNIX 管道相比存在一个缺点。考虑以下内容:command1 && command2 || command3。我认为这是很常见的模式。
  • 是的,与正确的 && 和 || 相比,这有点小技巧。支持。
  • 因为(至少)PSv2,non-terminating 错误do$? 设置为$false:例如,$null = Get-Item \, nosuch; $? 输出$false。在 terminating 错误的情况下,默认情况下命令行/脚本将完全中止;如果您执行try / catch 错误,则$?catch 块中为$false,或者,如果catch 块为空,则紧随其后;例如,try { throw "terminating err" } catch { }; $?
  • ExecuteUntilError 函数很方便,但请更清楚地说明Out-Host 解决方案有多大的漏洞,因为它绕过了正常的成功输出流,因此阻止了通过发送输出管道或将其捕获在变量或文件中。
  • 解释您关于需要 3 个 $? 的声明:使用 cmdlet,$? 仅允许您区分“处理所有输入项成功”和“处理至少一个,但可能所有输入项都失败了”;换句话说:你无法区分部分失败和完全失败;解决方法是将输入计数与$Error.Count 中的更改进行比较。
【解决方案2】:

Powershell 7 preview 5 有它们。 我不知道为什么在没有通知或解释的情况下将其删除。 https://devblogs.microsoft.com/powershell/powershell-7-preview-5/ 这将根据问题要求给出两个命令的输出。

echo 'hello' && echo 'there'
hello
there

echo 'hello' || echo 'there'
hello

【讨论】:

  • 这是正确答案。如果你认真使用 powershell,请使用 powershell-preview 巧克力包。
【解决方案3】:

为了简化多步脚本 doThis || exit 1 真的很有用,我使用类似的东西:

function ProceedOrExit { 
    if ($?) { echo "Proceed.." } else { echo "Script FAILED! Exiting.."; exit 1 } 
}

doThis; ProceedOrExit
doNext

# or for long doos
doThis
ProceedOrExit
doNext

【讨论】:

    【解决方案4】:

    更新PowerShell [Core] 7.0 引入了&&|| 支持 - 请参阅this answer


    Bash 的 /cmd&&|| 控制运算符没有 Windows PowerShell 等效项,并且由于您无法定义自定义运算符,因此没有好的解决方法强>。

    • Keith Hill's answer 中基于| Out-Host 的解决方法受到严重限制,因为它只能将正常命令输出发送到控制台(终端),从而阻止输出通过管道或被捕获在变量或文件中。

    this answer中查找背景信息。

    【讨论】:

      【解决方案5】:

      最简单的解决方案是使用

      powershell command1 && powershell command2
      

      在 cmd shell 中。当然,你不能在 .ps1 脚本中使用它,所以有这个限制。

      【讨论】:

      • @FrancescoMantovani,正确,但这里的 && 不在 powershell 中,它在 cmd shell 中。我在这里的回答是使用 cmd 将 2 个 powershell 命令串在一起(都打印了完整的输出)。
      【解决方案6】:

      更长的路见下文

      try {
        hostname
        if ($lastexitcode -eq 0) {
          ipconfig /all | findstr /i bios
        }
      } catch {
        echo err
      } finally {}
      

      【讨论】:

      • 不需要try / catch,因为它只在terminating错误时需要,外部实用程序如hostnameipconfigfindstr 无法触发。仅当您想知道由外部实用程序设置的特定退出代码时才需要检查 $LASTEXITCODE - 抽象的成功或失败反映在 $? 中,就像使用本机 cmdlet 一样。顺便说一句:请format your code properly
      【解决方案7】:

      随着 Powershell 7.0 的发布,支持 &&||

      https://devblogs.microsoft.com/powershell/announcing-powershell-7-0/

      New operators:
        Ternary operator: a ? b : c
        Pipeline chain operators: || and &&
        Null coalescing operators: ?? and ??=
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多