CMD管道与Powershell管道不同? [英] CMD pipe different form Powershell pipe?

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

问题描述

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

node .distGameNode.js |pino-漂亮

在 CMD 中运行它我得到了我的格式化输出但是在 powershell 中运行它我什么也得不到.我读到 Powershell 在管道时使用对象,所以我尝试了

node .distGameNode.js |外串-Stream |pino-漂亮

但这也行不通.

为什么它在 CMD 中有效,而在 Powershell 中无效?谢谢:)

解决方案

注意:问题中描述的特定pino-pretty 问题通过以下信息解决.Lukas(OP)已在

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

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

  • Invoke-WithEncoding一样,Debug-NativeInOutput支持-Encoding参数,所以如果你传递-EncodingAnsi 到上面的调用,你会看到 Python 的输出被正确解码.

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

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

node .distGameNode.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 .distGameNode.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 in the console window is problematic, and this comment on GitHub issue #14945 proposes a way to resolve this (for PowerShell (Core) only) in the future.

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

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