Powershell可执行文件未输出到STDOUT

5

通过一个已安装nuget并在路径中的powershell脚本,我正在尝试执行一个可执行文件(如果有影响,则为.net)...但由于某种原因,我无法在命令窗口中显示STDOUT。

nuget install mdoc -OutputDirectory packages -ExcludeVersion

start-process "packages/mdoc/tools/mdoc.exe" "--version"

echo "done"

这个应该输出为mdoc 5.7.2(在本文发布时,是最新版本)。但你会看到Nuget的输出,然后是done
你有什么想法,为什么它没有显示出来?

4
你可以使用 Start-Process -NoNewWindow 命令来启动程序,也可以直接运行程序,命令如下:& "packages/mdoc/tools/mdoc.exe" --version - Ansgar Wiechers
1
我不明白为什么很多人认为必须使用 Start-Process 才能让 PowerShell 运行可执行文件。这似乎是一个普遍的误解。 - Bill_Stewart
@AnsgarWiechers 和 @Bill_Stewart,我应该表达得更清楚...我确实尝试使用&符号来执行程序,并获得了相同的结果。 - Joel Martinez
但是,我也尝试添加了“-Wait”和“-NoNewWindow”,但没有任何效果。 - Joel Martinez
1个回答

17
正如Ansgar的评论所示:在Windows上,Start-Process默认情况下异步地在一个新的控制台窗口中运行控制台程序。
如果该程序很快完成,您可能只会看到新的控制台窗口闪现一下,因为它很快就会打开和关闭,或者您可能完全错过闪烁 - 无论哪种方式,其输出都不会显示在调用者的控制台窗口中。
Start-Process调用中添加-Wait将使调用同步进行,添加-NoNewWindow将使其在同一控制台中运行,但调用PowerShell会话将无法捕获或重定向调用的程序的输出 - 参见下文。
退一步:如果要以同步方式运行控制台程序,并将其标准流连接到PowerShell的流,请不要使用Start-Process,而是直接调用此类程序。
packages/mdoc/tools/mdoc.exe --version

如果外部程序的路径/名称必须被引用(因为其路径包含空格)和/或存储在变量中,只需使用 &,即调用运算符来调用它:
# Via a quoted string:
& "packages/mdoc/tools/mdoc.exe" --version

# Via a variable:
$exePath = "packages/mdoc/tools/mdoc.exe"
& $exePath --version

使用直接调用方法可以带给你以下好处:
  • 默认同步执行
  • 能够捕获和/或重定向被调用程序的标准输出和标准错误流。
  • 通过PowerShell的自动变量$LASTEXITCODE获得对程序进程退出代码的访问。

综合你后来的评论所说:

nuget install mdoc -OutputDirectory packages -ExcludeVersion

$exePath = "packages/mdoc/tools/mdoc.exe"

& $exePath --version

"done"

这将在打印done之前(在撰写本文时)打印版本号 - mdoc 5.7.2 - 在Microsoft Windows 10 Pro上的Windows PowerShell v5.1.17134.48(64位;版本1709,OS Build: 16299.371)上进行验证。


可选阅读:从外部程序中“捕获”stdout / stderr输出:

要捕获 stdout 输出,只需将调用分配给变量即可:

$version = & $exePath --version  # $version receives stdout output as an *array of lines*

$version接收一个字符串标量(单个字符串),如果只有1行输出,或者是表示输出行的字符串数组

要同时捕获stderr输出,请使用重定向2>&1:

[string[]] $allOutput = & $exePath --version 2>&1

请注意将 [string[]] 转换,以确保 stderr 行也被捕获为字符串。

  • 默认情况下,它们被捕获为 [System.Management.Automation.ErrorRecord] 实例,在 Windows PowerShell 中会有些混淆,因为它们会打印为 PowerShell 错误-此问题已在 PowerShell Core 中得到解决。

  • 相反,如果您不转换返回的数组元素的类型为字符串,您可以使用 -is [System.Management.Automation.ErrorRecord] 检查每个元素,以确定它是来自 stdout 还是 stderr。

    • 此答案 使用此方法在与 2>&1 合并后将 stdout 行与 stderr 行分开,以便它们可以保存到单独的文件中(在 Windows PowerShell 中,这需要显式地将 [System.Management.Automation.ErrorRecord] 实例字符串化)。

注意: 当 PowerShell 与外部程序通信时,会涉及字符编码问题: 有关详细信息,请参见 此答案


[1] 或者基于 .NET 的 API System.Diagnostics.Process
关于何时适合使用 Start-Process,请参见GitHub 文档问题 #6239


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接