Powershell类似于Bash的`set -e`

Col*_*nic 8 .net bash powershell

我怎样才能让Powershell像旗帜一样表现得像Bash set -eset -o errexit使Bash脚本"如果一个简单的命令以非零状态退出则立即退出".

我以为我可以通过设置来做到这一点,$ErrorActionPreference="Stop"但这似乎不起作用.假设我有一个脚本a.ps1

$ErrorActionPreference="Stop"
& cmd /c "exit 1"
echo "cmd exited `$LastExitCode=$LastExitCode and `$?=$?"
Run Code Online (Sandbox Code Playgroud)

如果我运行它

.\a. ; echo "a.ps1 exited `$LastExitCode=$LastExitCode `$?=$?"
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是它打印出来

cmd exited $LastExitCode=1 and $?=False
a.ps1 exited $LastExitCode=1 $?=True
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?!我希望a.ps1在第一行之后退出,抛出错误并设置$?为假.

有没有官方文档解释$ ErrorActionPreference?所有我发现了这个帖子上关于咖啡博客.

Joe*_*oey 11

$ErrorActionPreference 按预期工作,只是本机程序的退出代码并不像PowerShell cmdlet那样表现良好.

对于cmdlet错误条件很容易确定:是否发生了异常?因此,以下内容无法Write-Host通过$ErrorActionPreference设置为Stop:

Write-Error blah
Run Code Online (Sandbox Code Playgroud)

要么

Get-ChildItem somepathwhichsurelydoesntexisthere
Run Code Online (Sandbox Code Playgroud)

对于本机程序,退出代码为零通常表示没有发生错误,但这仅仅是一种约定,因为非零退出代码表示错误.你会说如果choice存在退出代码为1,那么这是一个错误吗?

处理此问题的唯一可靠方法是在运行本机命令后检查退出代码并在需要时自行处理.PowerShell并不试图猜测结果意味着什么,因为在这种情况下,约定不足以保证默认行为.

如果你想让生活更轻松,你可以使用一个功能:

function Invoke-NativeCommand {
  $command = $args[0]
  $arguments = $args[1..($args.Length)]
  & $command @arguments
  if (!$?) {
    Write-Error "Exit code $LastExitCode while running $command $arguments"
  }
}
Run Code Online (Sandbox Code Playgroud)

但一般来说,许多程序需要不同的处理,因为它们不遵守所述惯例.

  • 糟糕,这令人沮丧。感谢您的功能,我将使用它。 (2认同)
  • 该功能效果很好。我将测试`!$?`更改为`$ LastExitCode -ne 0`,因为`$?`已损坏http://stackoverflow.com/questions/10666101/powershell-lastexitcode-0-but-false-redirecting-stderr-给-给-nat (2认同)
  • 我确实理解有些程序可能会行为不端,因此具有一定的灵活性很重要,但实际上,我从 PowerShell 脚本调用的几乎所有命令行工具都很好地遵循了这一约定。当然,我的大部分经验都与构建脚本有关,但我确实认为约定比这个答案听起来要强得多。我认为它足够强大,可以保证内置一些东西,即使它只是一个像这里的函数,所以我们不必在我们所有的脚本/包中重新定义它。 (2认同)