CMD管的形式与Powershell管不同? [英] CMD pipe different form Powershell pipe?
问题描述
我正在尝试将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 inchcp
.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
- This direct-to-display printing can sometimes hide encoding problems, because some programs, notably
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Θ'
. (TheInput*
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屋!