将文本管道到外部程序会附加一个尾随换行符

时间:2018-01-21 20:33:43

标签: linux powershell hash pipe newline

我一直在比较多个系统之间的哈希值,并且惊讶地发现PowerShells哈希值与其他终端的哈希值不同。

Linux终端(CygWin,Bash for Windows等)和Windows命令提示符都显示相同的哈希,而PowerShell显示不同的哈希值。

Linux_Vs_PShell_Hash_Compare.png

这是使用SHA256测试的,但在使用其他算法(如md5)时发现了同样的问题。

编码更新:

尝试更改PShell编码,但它对返回的哈希值没有任何影响。

[Console]::OutputEncoding.BodyName 
iso-8859-1
[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
utf-8

GitHub PowerShell问题

https://github.com/PowerShell/PowerShell/issues/5974

2 个答案:

答案 0 :(得分:3)

<强> TL; DR:

键是为了避免 PowerShell的管道支持本机shell,以便防止隐含添加尾随换行符:< / p>

  • 如果您在 Unix 类平台上运行命令(使用PowerShell Core ):
sh -c "printf %s 'string' | openssl dgst -sha256 -hmac authcode"

printf %secho -n便携式替代方案。如果字符串包含'个字符, double ,或者使用`"...`"引用。

  • 如果您需要通过cmd.exe Windows 上执行此操作,事情变得更加棘手,因为cmd.exe不直接支持回显没有尾随换行符:
cmd /c "<NUL set /p =`"string`"| openssl dgst -sha256 -hmac authcode"

请注意, |之前必须没有空格才能生效。有关此解决方案的解释和限制,请参阅我的this answer

只有当字符串包含 Windows PowerShell中运行的非ASCII字符时,才会出现编码问题;在该事件中,首先将$OutputEncoding设置为目标实用程序所期望的编码,通常为UTF-8:$OutputEncoding = [Text.Utf8Encoding]::new()

  • PowerShell,从Windows PowerShell v5.1 / PowerShell Core v6.0.0起,总是在您发送字符串时附加尾随换行符一个通过管道连接到外部实用程序,这就是你正在观察的差异的原因(尾随换行仅在Unix平台上是LF,在Windows上是CRLF序列)。

  • 此外,PowerShell的管道总是以 text 为基础,当涉及到管道数据到外部程序时;内部基于UTF-16LE的PowerShell(.NET)字符串根据存储在自动$OutputEncoding变量中的编码进行转码,该变量在 Windows PowerShell中默认为仅ASCII编码,并且PowerShell Core 中的UTF-8编码(在Windows和类Unix平台上)。

  • 因此,PowerShell中的echo -n 生成不带尾随换行符的字符串的事实因此偶然到您的问题中;为了完整起见,这是一个解释:

    • echo是PowerShell的Write-Output cmdlet的别名,在外部程序的管道环境中 - 将 text 写入标准在 next 管道段中输入程序(类似于Bash / cmd.exe的echo)。
    • -n被解释为Write-Output的{​​{1}}切换的(明确的)缩写。
    • -NoEnumerate仅在编写多个对象时适用,因此在此处无效。
    • 因此,简而言之:在PowerShell中,-NoEnumerateecho -n "string"相同,后者 - 因为只输出一个字符串 - 与Write-Output -NoEnumerate "string"相同,后者依次为Write-Output "string" ,就像使用"string"一样,依赖于PowerShell的隐式输出行为。
    • Write-Output没有选项可以抑制尾随换行符,即使这样做,使用管道传输到外部程序也会将其添加回来。

答案 1 :(得分:1)

Linux终端和PowerShell使用不同的编码。因此echo -n "string"产生的实际字节是不同的。我在我的Linux Mint终端和Windows 10 PowerShell上尝试过它。这就是我得到的:

Linux Mint:

73 74 72 69 6E 67

Windows 10:

FF FE 73 00 74 00 72 00 69 00 6E 00 67 00 0D 00 0A 00

似乎Linux终端使用UTF-8,而Windows PowerShell使用带有BOM的UTF-16。同样在PowerShell中,您无法使用&#39; -n&#39; echo的参数。因此,echo将换行符\r\n0D 00 0A 00)放在&#34;字符串&#34;的末尾。

编辑:如下所述mklement0,Windows PowerShell在管道传输时默认使用ASCII。