CMD管的形式与Powershell管不同? [英] CMD pipe different form Powershell pipe?

查看:49
本文介绍了CMD管的形式与Powershell管不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Node.js输出通过管道传输到preatty-pino

node.\ dist \ GameNode.js |皮诺漂亮

在CMD中运行此命令,得到格式化的输出,但是在Powershell中运行却什么也没得到.我读到Powershell在进行管道传输时正在使用对象,所以我尝试了

node.\ dist \ GameNode.js |流外串流|皮诺漂亮

但这也不起作用.

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

解决方案

注意:问题中描述的特定 pino-pretty 问题无法通过 解决以下信息.卢卡斯(OP)在

  • 请注意 DecodedOutput 属性,根据解释Python的输出显示 mis 解码的结果作为 OEM -而不是ANSI编码:'eΘ'.( Input * 属性为空白,因为该命令不涉及将数据传递给 Python脚本.)

  • 与之相反,使用 direct-to-display 可以很好地打印输出 prints (因为Python然后-并且只有-使用Unicode),>隐藏问题,但是只要您要以编程方式处理输出-捕获变量,发送到管道中的另一个命令,重定向到文件-编码问题就会浮出水面

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

  • 输出反映了以下事实:在PowerShell(核心)中, $ OutputEncoding 默认为UTF-8,而在Windows PowerShell中则默认为ASCII(!).这种与实际编码的不匹配实际上是有问题的,并且有关GitHub问题的评论#提出了一种将来解决此问题的方法(仅适用于PowerShell(Core)).

I am trying to pipe Node.js output to preatty-pino

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

running this in the CMD I get my formated output but running it inside a powershell I get nothing. I read that Powershell is using objects when piping, so I tried

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

But this also does not work.

Why does it work inside CMD but not inside Powershell ? Thanks :)

解决方案

Note: The specific pino-pretty problem described in the question is not resolved by the information below. Lukas (the OP) has filed a bug report here.

It's surprising that you get nothing, but the fundamental difference is:

  • cmd.exe's pipeline conducts raw data, i.e. byte streams (which a given program receiving the data may or may not itself interpret as text).

  • PowerShell's pipeline, when talking to external programs, conducts only text (strings), which has two implications:

    • On piping data to an external program, text must be encoded, which happens based on the character encoding stored in preference variable $OutputEncoding.

    • On receiving data from an external program, data must be decoded, which happens based on the character encoding stored in [Console]::OutputEncoding, which by default is the system's OEM code page, as reflected in chcp.

      • This decoding happens invariably, irrespective of whether the data is then further processed in PowerShell or passed on to another external program.

        • This sometimes problematic lack of ability to send raw data through PowerShell's pipeline even between two external programs is discussed in this answer.
      • The only exception is if external-program output is neither captured, sent on through the pipeline, nor redirected to a file: in that case, the data prints straight to the console (terminal), but only in a local console (when using PowerShell remoting to interact with a remote machine, decoding is again invariably involved).

        • This direct-to-display printing can sometimes hide encoding problems, because some programs, notably python, use full Unicode support situationally in that case; that is, the output may print fine, but when you try to process it further, encoding problems can surface.
        • A simple way to force decoding is to enclose the call in (...); e.g.,
          python -c "print('eé')" prints fine, but
          (python -c "print('eé'))" surfaces an encoding problem; see the bottom section for more information

While console applications traditionally use the active OEM code page for character encoding and decoding, Node.js always uses UTF-8.

Therefore, in order for PowerShell to communicate properly with Node.js programs, you must (temporarily) set the following first:

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

If you want to fundamentally switch to UTF-8, either system-wide (which has far-reaching consequences) or only for PowerShell console windows, see this answer.


As an aside: an intermediate Out-String -Stream pipeline segment is never needed for relaying an external program's output - it is effectively (a costly) no-op, because streaming stdout output line by line is what PowerShell does by default. In other words: it is not surprising that it made no difference in your case.


Optional reading: Convenience function Invoke-WithEncoding and diagnostic function Debug-NativeInOutput for ad-hoc encoding needs / diagnosis:

If switching all PowerShell consoles to UTF-8 isn't an option and/or you need to deal with "rogue" programs that use a specific encoding other than UTF-8 or the active OEM code page, you can install:

  • Function Invoke-WithEncoding, which temporarily switches to a given encoding when invoking an external program, directly from this Gist as follows (I can assure you that doing so is safe, but you should always check):

# Download and define advanced function Invoke-WithEncoding in the current session.
irm https://gist.github.com/mklement0/ef57aea441ea8bd43387a7d7edfc6c19/raw/Invoke-WithEncoding.ps1 | iex

  • Function Debug-NativeInOutput, which helps diagnose encoding problems with external programs, directly from this Gist as follows (again, you should check first):

# Download and define advanced function Debug-NativeInOutput in the current session.
irm https://gist.github.com/mklement0/eac1f18fbe0fc2798b214229b747e5dd/raw/Debug-NativeInOutput.ps1 | iex


Below are example commands that use a python command to print an accented character.

Like Node.js, Python's behavior is nonstandard, although it doesn't use UTF-8, but the system's active ANSI(!) code page (rather than the expected OEM code page).

That is, even if you switch your PowerShell consoles UTF-8, communication with Python scripts won't work properly by default, unless extra effort is made, which Invoke-WithEncoding can encapsulate for you:

Note: I'm using Python as an example here, to illustrate how the functions work. It is possible to make Python use UTF-8, namely by either setting environment variable PYTHONUTF8 to 1 or - in v3.7+ - by passing parameter -X utf8 (case-exactly).


Invoke-WithEncoding example:

# 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é

  • Note that Invoke-WithEncoding ensures that actual decoding to a .NET string happens before it outputs, so that encoding problems aren't accidentally masked by the direct-to-display output seemingly being correct on Windows (see below for more).

  • -WindowsOnly is for cross-platform compatibility and ensures that the encoding is only applied on Windows in this case (on Unix, Python uses UTF-8).


Debug-NativeInOutput example:

With the PowerShell console at its default, using the system's OEM code page, you'll see the following output with the same Python command, calling from PowerShell (Core) 7.1:

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

  • Note the DecodedOutput property, showing the mis-decoded result based on interpreting Python's output as OEM- rather than as ANSI-encoded: 'eΘ'. (The Input* properties are blank, because the command did not involve piping data to the Python script.)

  • By contrast, with direct-to-display printing the output prints fine (because Python then - and only then - uses Unicode), which hides the problem, but as soon you want to programmatically process the output - capture in a variable, send to another command in the pipeline, redirect to a file - the encoding problem will surface.

  • Like Invoke-WithEncoding, Debug-NativeInOutput supports an -Encoding parameter, so if you pass -Encoding Ansi to the call above, you'll see that Python's output is decoded properly.

  • The output reflects the fact that, in PowerShell (Core), $OutputEncoding defaults to UTF-8, whereas in Windows PowerShell it defaults to ASCII(!). This mismatch with the actual encoding in effect is problematic, and this comment on GitHub issue # proposes a way to resolve this (for PowerShell (Core) only) in the future.

这篇关于CMD管的形式与Powershell管不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆