返回

PowerShell 中 $? 和 $LastExitCode 的陷阱:标准错误重定向的迷惑

windows

PowerShell 中 ? 和 LastExitCode 的陷阱:标准错误重定向的混乱

作为一名经验丰富的程序员,在使用 PowerShell 脚本时,我遇到了一个令人困惑的现象:LastExitCode 为 0 但 ? 为 False。经过一番调查,我发现这与标准错误流的重定向有关,它会混淆 PowerShell 确定命令成功与否的方式。

理解 ? 和 LastExitCode

在深入探讨之前,让我们快速回顾一下 ? 和 LastExitCode 这两个关键的 PowerShell 变量:

  • **?** :此自动变量指示前一个命令是否成功执行。成功时,? 为 True,失败时为 False。
  • $LastExitCode :此自动变量存储前一个命令的退出代码。0 表示成功,非 0 表示失败。

标准错误重定向

问题出现于当我们将标准错误流重定向到标准输出流时。这是 PowerShell 中一种常见的做法,但它会产生意外后果。

案例 1:成功重定向

echo Hello from standard error 1>&2

此命令将标准错误消息 "Hello from standard error" 发送到控制台,就像标准输出消息一样。在这种情况下,? 和 LastExitCode 的值是预期的:

  • $?:True(表示成功)
  • $LastExitCode:0(表示成功)

案例 2:NativeCommandError

& cmd /c "echo Hello from standard error 1>&2" 2>&1

此命令进一步将标准错误流重定向到标准输出流。但是,这会导致 PowerShell 遇到 NativeCommandError。这是因为 PowerShell 期望标准错误流和标准输出流是分开的,而重定向命令打破了这种分离。

$? 为 False 的原因

尽管 LastExitCode 为 0(表示命令执行成功),但 ? 却为 False。这是因为 PowerShell 将标准错误重定向视为命令失败的标志。即使命令本身成功执行,重定向的存在也会导致 $? 为 False。

实际影响

在实际应用中,这种行为会导致意外结果。例如,在脚本中检查 ? 变量以确定命令是否成功执行时,即使命令本身没有失败,重定向也会导致 ? 为 False。

解决方法

为了避免此问题,可以在重定向之前捕获标准错误流。一种方法是使用重定向运算符 '>>' 将标准错误输出追加到文件中:

& cmd /c "echo Hello from standard error 1>&2" 2>> error.txt

通过这种方式,标准错误消息不会被重定向到标准输出流,并且 $? 将准确地反映命令执行的成功状态。

常见问题解答

  • 什么是标准错误流?

标准错误流用于显示命令执行期间发生的错误和警告消息。

  • 为什么 ? 和 LastExitCode 有时会不一致?

标准错误流的重定向会导致 PowerShell 将此视为命令失败的标志,即使命令本身成功执行也是如此。

  • 如何捕获标准错误流?

使用重定向运算符 '>>' 将标准错误输出追加到文件中。

  • 重定向标准错误流有什么好处?

重定向标准错误流可用于将错误和警告消息存储在日志文件中,以便进行分析和故障排除。

  • LastExitCode 为 0 但 ? 为 False 时该怎么办?

首先检查是否重定向了标准错误流。如果是,请使用前面提到的方法来捕获错误消息。