PowerShell 中 $? 和 $LastExitCode 的陷阱:标准错误重定向的迷惑
2024-03-28 02:37:51
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 时该怎么办?
首先检查是否重定向了标准错误流。如果是,请使用前面提到的方法来捕获错误消息。