将文本传输到外部程序会附加尾随换行符
- 2024-10-30 08:35:00
- admin 原创
- 45
问题描述:
我一直在比较多个系统之间的哈希值,惊讶地发现 PowerShell 的哈希值与其他终端的哈希值不同。
Linux 终端(CygWin、Windows 的 Bash 等)和 Windows 命令提示符都显示相同的哈希值,而 PowerShell 显示不同的哈希值。
使用 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
解决方案 1:
更新:
PowerShell(核心) v7.4+现在支持使用外部程序处理原始字节(参见此答案),从而实现以下更简单的解决方案:
在类Unix平台上:
# PS v7.4+ only, on Unix-like platforms
# No newline will be appended; the raw byte output from external program printf
# is passed through.
printf %s 'string' | openssl dgst -sha256 -hmac authcode
在Windows上(也适用于 Unix):
# PS v7.4+ only, on any supported platform.
# Send the *byte* representation of the string to external program openssl.
# If you were to send the string directly, PowerShell would append a newline.
, [Text.Encoding]::UTF8.GetBytes('string') | openssl dgst -sha256 -hmac authcode
因此,以下内容仅适用于Windows PowerShell和PowerShell (Core) v7.3-。
总结:
当 PowerShell 通过管道将字符串传输到外部程序时:
它使用存储在偏好变量中的字符编码对其进行编码
$OutputEncoding
它总是附加一个尾随的(适合平台的)换行符。
因此,关键是避免使用PowerShell 的管道而使用本机 shell 的管道,以防止隐式添加尾随换行符:
如果您在类Unix平台上运行命令(使用 PowerShell Core):
sh -c "printf %s 'string' | openssl dgst -sha256 -hmac authcode"
printf %s
是 的可移植替代方案echo -n
。如果字符串包含'
字符,请将其加倍或使用`"...
"`引号。
如果您需要在Windows上通过
cmd.exe
执行此操作,事情会变得更加棘手,因为cmd.exe
它不直接支持不带尾随换行符的回显:
cmd /c "<NUL set /p =`"string`"| openssl dgst -sha256 -hmac authcode"
请注意,此方法之前不能有空格。有关此解决方案的说明和限制,请参阅 此答案。|
仅当字符串包含非 ASCII 字符并且您在Windows PowerShell 中运行时,才会出现编码问题;在这种情况下,首先设置$OutputEncoding
为目标实用程序所需的编码,通常为 UTF-8:$OutputEncoding = [Text.Utf8Encoding]::new()
当您通过管道将没有换行符的字符串发送到外部实用程序时, PowerShell总会附加一个尾随换行符,这就是您观察到的差异的原因(尾随换行符在 Unix 平台上仅为 LF,在 Windows 上为 CRLF 序列)。
+ 您可以在 OP 打开的GitHub 问题 #5974中跟踪解决此问题的努力。
此外,在 Windows PowerShell 和 PowerShell (Core) 中,直到 v7.3.x 版本,在将数据传输到外部程序时,PowerShell 的管道始终是基于文本的;内部基于 UTF-16LE 的 PowerShell (.NET) 字符串根据存储在自动变量中的编码进行转码,在Windows
$OutputEncoding
PowerShell中默认为仅 ASCII 编码,在 PowerShell Core中默认为 UTF-8 编码(在 Windows 和类 Unix 平台上)。
+ ***PowerShell(核心)v7.4+*现在*支持*使用外部程序进行原始字节处理**- 请参阅此答案。
因此,
echo -n
PowerShell 中不会产生没有尾随换行符的字符串这一事实与您的问题无关;为了完整起见,这里有一个解释:
+ `echo`是 PowerShell cmdlet 的别名,在管道传输到*外部*程序`Write-Output`的上下文中,它将*文本写入下**一个*管道段中的程序标准输入(类似于 Bash/cmd.exe )。`echo`
+ `-n``Write-Output`被解释为开关的(明确的)缩写`-NoEnumerate`。
+ `-NoEnumerate`仅适用于写入*多个*对象时,因此这里没有效果。
+ 因此,简而言之:在 PowerShell 中,`echo -n "string"`与 相同`Write-Output -NoEnumerate "string"`,因为只输出一个字符串 - 与 相同`Write-Output "string"`,而这反过来又与仅使用 相同`"string"`,依赖于 PowerShell 的*隐式*输出行为。
+ `Write-Output`没有选项可以抑制尾随换行符,即使有,使用管道传输到*外部*程序也会将其添加回来。
解决方案 2:
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 中,您不能为 echo 使用“-n”参数。因此 echo 将换行符`(
0D 00 0A 00`) 放在“字符串”末尾。
编辑:正如mklement0下面所说,Windows PowerShell 在管道传输时默认使用 ASCII。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件