CMD管道与Powershell管道不同?

2024-09-28 05:17:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试将Node.js输出传输到preatty pino

node .\dist\GameNode.js | pino-pretty

在CMD中运行此命令可以获得格式化的输出,但在powershell中运行它却一无所获。 我读到Powershell在管道中使用对象,所以我尝试了

node .\dist\GameNode.js | Out-String -Stream | pino-pretty

但这也不起作用

为什么它在CMD中工作而在Powershell中不工作? 谢谢:)


Tags: 对象命令cmdnode管道distjspretty
1条回答
网友
1楼 · 发布于 2024-09-28 05:17:41

注:问题中描述的特定pino-pretty问题未通过以下信息解决。卢卡斯(OP)提交了一份错误报告。

令人惊讶的是,你什么也得不到,但是基本的区别是:

  • cmd.exe的管道执行原始数据,即字节流(接收数据的给定程序本身可能解释为文本

  • PowerShell的管道在与外部程序对话时,只执行文本(字符串),这有两种含义:

    • 在将数据传输到外部程序时,文本必须编码,这是基于preference variable ^{}中存储的字符编码发生的

    • 从外部程序接收数据时,必须对数据进行解码,该解码基于存储在[Console]::OutputEncoding中的字符编码,默认情况下,该编码是系统的OEM代码页,如chcp所示

      • 无论数据随后是在PowerShell中进一步处理还是传递到另一个外部程序,这种解码总是发生

        • 有时,即使在两个外部程序之间,也无法通过PowerShell管道发送原始数据,这一问题在this answer中讨论
      • 唯一的异常是外部程序输出既没有被捕获,也没有通过管道发送,也没有重定向到文件:在这种情况下,数据直接打印到控制台(终端),但只打印在本地控制台中(当使用PowerShell远程处理与远程机器交互时,解码同样不可避免地涉及到)

        • 这种直接显示打印有时会隐藏编码问题,因为某些程序,尤其是python,在这种情况下使用完全的Unicode支持;也就是说,输出可能会打印很好,但当您尝试进一步处理它时,编码问题可能会浮出水面
        • 强制解码的简单方法是将调用括在(...)中;例如
          python -c "print('eé')"打印的很好,但是
          (python -c "print('eé'))"显示了一个编码问题;有关详细信息,请参阅底部部分

控制台应用程序传统上使用活动OEM代码页进行字符编码和解码,Node.js始终使用UTF-8

因此,为了使PowerShell与Node.js程序正确通信,必须(临时)首先设置以下各项:

$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()

如果您想从根本上切换到UTF-8,或者在系统范围内(这会产生深远的影响)或者仅针对PowerShell控制台窗口,请参见this answer


顺便说一句:中继外部程序的输出永远不需要中间的Out-String -Stream管道段——这实际上是(代价高昂的)不可操作的,因为PowerShell默认情况下会逐行流式处理标准输出。换句话说,它对您的情况没有影响,这并不奇怪


可选阅读:方便功能Invoke-WithEncoding和诊断功能Debug-NativeInOutput用于特殊编码需求/诊断:

如果无法将所有PowerShell控制台切换到UTF-8,和/或您需要处理使用UTF-8或活动OEM代码页以外的特定编码的“流氓”程序,您可以安装:

  • 函数Invoke-WithEncoding,它在调用外部程序时直接从this Gist临时切换到给定的编码,如下所示(我可以向您保证这样做是安全的,但您应该始终检查):
# Download and define advanced function Invoke-WithEncoding in the current session.
irm https://gist.github.com/mklement0/ef57aea441ea8bd43387a7d7edfc6c19/raw/Invoke-WithEncoding.ps1 | iex
  • 函数Debug-NativeInOutput,它可以直接从this Gist诊断外部程序的编码问题,如下所示(同样,您应该先检查):
# Download and define advanced function Debug-NativeInOutput in the current session.
irm https://gist.github.com/mklement0/eac1f18fbe0fc2798b214229b747e5dd/raw/Debug-NativeInOutput.ps1 | iex

下面是使用python命令打印重音字符的示例命令

与Node.js一样,Python的行为也是非标准的,尽管它没有使用UTF-8,但系统的活动代码页(而不是预期的OEM代码页)

也就是说,即使您切换PowerShell控制台UTF-8,默认情况下,与Python脚本的通信也无法正常工作,除非进行额外的工作,Invoke-WithEncoding可以为您封装:

注意:我在这里使用Python作为示例,以说明函数是如何工作的。可以使Python使用UTF-8,即通过将环境变量PYTHONUTF8设置为1或在v3.7+中通过传递参数-X utf8(大小写完全相同)。


Invoke-WithEncoding示例:

# Outputs *already-decoded* output, so if the output *prints* fine, 
# then *decoding* worked fine too.
PS> Invoke-WithEncoding { python -c "print('eé')" } -Encoding Ansi -WindowsOnly
eé
  • 请注意,Invoke-WithEncoding确保对.NET字符串的实际解码发生在其输出之前,这样编码问题就不会被直接屏蔽,从而在Windows上显示输出似乎是正确的(有关更多信息,请参阅下文)

  • -WindowsOnly用于跨平台兼容性,并确保在这种情况下编码仅应用于Windows(在Unix上,Python使用UTF-8)


Debug-NativeInOutput示例:

在PowerShell控制台处于默认状态的情况下,使用系统的OEM代码页,使用相同的Python命令,从PowerShell(Core)7.1调用,您将看到以下输出:

PS> Debug-NativeInOutput { python -c "print('eé')" }

Debug-NativeInOutput

  • 注意DecodedOutput属性,它显示了mis-解码结果,该结果基于将Python的输出解释为OEM-而不是ANSI编码:'eΘ'。(由于该命令没有将数据管道化到Python脚本,Input*属性为空。)

  • 相比之下,使用直接显示打印输出可以打印精细(因为Python当时-而且只有那时-使用Unicode),这隐藏了问题,但是只要您想以编程方式处理变量中的输出捕获,就可以发送到管道中的另一个命令,重定向到文件-编码问题将浮出水面

  • Invoke-WithEncoding类似,Debug-NativeInOutput支持-Encoding参数,因此如果将-Encoding Ansi传递给上面的调用,您将看到Python的输出被正确解码

  • 输出反映了这样一个事实:在PowerShell(核心)中,$OutputEncoding默认为UTF-8,而在Windows PowerShell中它默认为ASCII(!)。这种与控制台窗口中实际编码的不匹配是有问题的,并且this comment on GitHub issue #14945提出了一种解决方法(仅适用于PowerShell(Core))将来解决此问题

相关问题 更多 >

    热门问题