【问题标题】:Automatically stop powershell script on bat errors在 bat 错误时自动停止 powershell 脚本
【发布时间】:2011-09-19 22:29:01
【问题描述】:

通常可以使用 $ErrorActionPreference 来停止执行错误的 PS 脚本,如下例所示,它使用了无效的颠覆命令。脚本在第一个命令后退出。

$ErrorActionPreference='Stop'
svn foo
svn foo

使用 maven 命令 (mvn.bat) 尝试相同的操作会执行这两个命令。

$ErrorActionPreference='Stop'
mvn foo
mvn foo

最初我怀疑 mvn.bat 没有设置错误代码,而 PS 只是没有看到错误。然而,$?当 PS 在第一个错误后退出时,设置正确,如下所示:

mvn foo
if (-not $?) {exit 1}
mvn foo

所以这是我的问题:鉴于 svn.exe 和 mvn.bat 都在失败时设置了错误代码,为什么 PS 脚本在 mvn 错误后没有停止。我发现全局设置“$ErrorActionPreference=Stop”而不是在每个命令后执行“if (-not $?) {exit 1}”以在错误时终止要方便得多。

【问题讨论】:

    标签: powershell maven


    【解决方案1】:

    并非所有命令行程序都以相同的方式提供错误。有些设置了退出代码。有些没有。有些使用错误流,有些则不使用。我见过一些命令行程序实际上将所有内容都输出到错误中,并且总是输出非零返回码。

    因此,人们无法对它是否成功运行做出真正安全的猜测,因此将这种行为编码到 PowerShell 中几乎是不可能的。

    $errorActionPreference 实际上会在 .exe 写入错误流时停止脚本,但许多 .exe 会将常规输出写入控制台并且从不填充错误流。

    但它不会可靠地工作。就此而言,$? 也不会。如果 exe 返回 0 并且不写入错误 $?会是真的。

    虽然在 PowerShell 中处理每个单独的 .exe 及其错误可能会让人头疼,但这是一个很好的例子,说明了为什么 PowerShell 的高度结构化的输出/错误/详细/警告/调试/进度流和一致Cmdlet 中的错误行为胜过普通的旧 .EXE 工具。

    希望对你有帮助

    【讨论】:

    • 谢谢,有帮助。但与此同时,我认为 PS 开发团队根据错误流上的活动检测故障的决定并不是很有启发性。从一开始,程序就会返回一个非零退出代码来表示错误。也许不是每个程序都这样做,但 unix shell 脚本在这个约定下工作得很好。这不是关于 PS 有多棒,而是关于它与外部程序的集成程度。
    • 我建议您没有阅读回复。您会惊讶于退出代码甚至错误流上的消息是多么不可靠。 PowerShell 确实将非零退出代码解释为失败。美元?反映了这一点。但它不应该完全停止脚本,因为这意味着任何单个数据的单个问题总是会停止批量操作。这会使更多的操作变得更加困难。
    • 我确实非常仔细地阅读了回复。但我的观点仍然有效。如果我将 $errorActionPreference 设置为“Stop”,那么我希望 PS 能够适应它。如果您阅读了我最初的帖子,脚本会停止 svn.exe(可能是因为它也写入错误流)。但在 mvn.bat 的情况下,脚本不会停止(可能是因为它没有写入错误流)。
    • 完整评论:我确实阅读了回复。但是,如果我将 $errorActionPreference 设置为“Stop”,那么我希望 PS 能够适应它。在我最初的帖子中,脚本为 svn.exe 停止(因为它也写入错误流)。但是对于 mvn.bat 脚本不会停止(因为它不会写入错误流)。所以,PS 在 $? 中记录了一个进程的退出代码,但它并没有用它来猜测进程是否失败。如果我想在其中一个命令失败后停止脚本,那么我必须在每个命令之后用“if (-not $?) {exit 1}”乱扔我的代码。
    【解决方案2】:

    $ErrorActionPreference 控制 PowerShell 在命令行开关和 PowerShell 函数方面的行为——它对“遗留”命令的退出代码不敏感。我自己仍在为这个设计决策寻找解决方法——关于这个问题,请参考这个线程:How to stop a PowerShell script on the first error?。您可能会得出结论,这个自定义的“exec”函数是最好的解决方案:http://jameskovacs.com/2010/02/25/the-exec-problem/

    关于 stop-on-stderr 行为,我无法在 PowerShell 3 中重现此行为:

    Invoke-Command
    {
      $ErrorActionPreference='Stop'
      cmd /c "echo hi >&2"          # Output to stderr (this does not cause termination)
      .\DoesNotExist.exe            # Try to run a program that doesn't exist (this throws)
      echo bye                      # This never executes
    }
    

    更新:stop-on-stderr 行为似乎在使用 PS 远程处理时生效。

    【讨论】:

      猜你喜欢
      • 2022-11-10
      • 2010-12-20
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      • 1970-01-01
      • 2014-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多