gpt4 book ai didi

windows - $LastExitCode=0,但 $?=False 在 PowerShell 中。将 stderr 重定向到 stdout 会给出 NativeCommandError

转载 作者:可可西里 更新时间:2023-11-01 11:59:08 26 4
gpt4 key购买 nike

为什么 PowerShell 在下面的第二个示例中显示出令人惊讶的行为?

首先,举一个理智行为的例子:

PS C:\> & cmd /c "echo Hello from standard error 1>&2"; echo "`$LastExitCode=$LastExitCode and `$?=$?"
Hello from standard error
$LastExitCode=0 and $?=True

没有惊喜。我向标准错误打印一条消息(使用 cmdecho)。我检查变量 $?$LastExitCode。正如预期的那样,它们分别等于 True 和 0。

但是,如果我要求 PowerShell 通过第一个命令将标准错误重定向到标准输出,我会得到一个 NativeCommandError:

PS C:\> & cmd /c "echo Hello from standard error 1>&2" 2>&1; echo "`$LastExitCode=$LastExitCode and `$?=$?"
cmd.exe : Hello from standard error
At line:1 char:4
+ cmd <<<< /c "echo Hello from standard error 1>&2" 2>&1; echo "`$LastExitCode=$LastExitCode and `$?=$?"
+ CategoryInfo : NotSpecified: (Hello from standard error :String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

$LastExitCode=0 and $?=False

我的第一个问题,为什么会出现 NativeCommandError?

其次,为什么cmd运行成功,$LastExitCode为0时,$?为False? PowerShell 的文档 about automatic variables没有明确定义 $?。当且仅当 $LastExitCode 为 0 时,我一直认为它为 True,但我的示例与此相矛盾。


以下是我在现实世界(简化版)中遇到这种行为的方式。这真的是 FUBAR。我正在从另一个调用一个 PowerShell 脚本。内部脚本:

cmd /c "echo Hello from standard error 1>&2"
if (! $?)
{
echo "Job failed. Sending email.."
exit 1
}
# Do something else

简单地以 .\job.ps1 运行它,它工作正常,并且没有发送电子邮件。但是,我是从另一个 PowerShell 脚本调用它的,记录到文件 .\job.ps1 2>&1 > log.txt。在这种情况下,将发送一封电子邮件!您在脚本外部使用错误流执行的操作会影响脚本的内部行为。 观察现象会改变结果。这感觉更像是量子物理学而不是脚本!

[有趣的是:.\job.ps1 2>&1 可能会或不会爆炸,这取决于你在哪里运行它]

最佳答案

(我使用的是 PowerShell v2。)

$?”变量记录在 about_Automatic_Variables 中:

$?  Contains the execution status of the last operation

这是指最近的 PowerShell 操作,而不是上次外部命令,后者是您在 $LastExitCode 中获得的内容。

在您的示例中,$LastExitCode 为 0,因为最后一个外部命令是 cmd,它成功回显了一些文本。但是 2>&1 导致发送到 stderr 的消息被转换为输出流中的错误记录,这告诉 PowerShell 在上次操作,导致 $?False

为了进一步说明这一点,请考虑以下内容:

> java -jar foo; $?; $LastExitCodeUnable to access jarfile fooFalse1

$LastExitCode 是 1,因为那是 java.exe 的退出代码。 $? 为 False,因为 shell 做的最后一件事失败了。

但如果我所做的只是将它们调换:

> java -jar foo; $LastExitCode; $?Unable to access jarfile foo1True

... 然后 $? 为 True,因为 shell 所做的最后一件事是向主机打印 $LastExitCode,这是成功的。

最后:

> &{ java -jar foo }; $?; $LastExitCodeUnable to access jarfile fooTrue1

...这似乎有点违反直觉,但 $? 现在是 True,因为脚本 block 的执行成功,即使在其中运行的命令不是。


返回到 2>&1 重定向....导致错误记录进入输出流,这就是关于 NativeCommandError 。 shell 正在转储整个错误记录。

当您只想通过管道将 stderr stdout 放在一起以便将它们合并到一个日志文件中时,这可能会特别烦人或者其他的东西。谁想让 PowerShell 插进他们的日志文件???如果我执行 ant build 2>&1 >build.log,那么任何转到 stderr 的错误都会附加 PowerShell 的 nosey $0.02,而不是在我的日志文件中获取干净的错误消息。

但是,输出流不是文本 流!重定向只是对象 管道的另一种语法。错误记录是对象,因此您所要做的就是在重定向之前将该流上的对象转换为字符串:

来自:

> cmd /c "echo Hello from standard error 1>&2" 2>&1cmd.exe : Hello from standard errorAt line:1 char:4+ cmd &2" 2>&1    + CategoryInfo          : NotSpecified: (Hello from standard error :String) [], RemoteException    + FullyQualifiedErrorId : NativeCommandError

收件人:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | %{ "$_" }Hello from standard error

...并重定向到一个文件:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | %{ "$_" } | tee out.txtHello from standard error

...或者只是:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | %{ "$_" } >out.txt

关于windows - $LastExitCode=0,但 $?=False 在 PowerShell 中。将 stderr 重定向到 stdout 会给出 NativeCommandError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10666101/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com