Powershell 的管道兼容性

2020-07-29 13:44:31 +08:00
 ColinZeb

在 windows 上试用 gzip 遇到个管道的坑。

windows 上是没有 gzip 命令的。

首先安装 scoop install gzip

压缩命令一般这么写 cat script.ps1|gzip >script.gz

这个写法在 bash zsh 和 cmd 都能正常工作,但是 pwsh 不行,甚至 powershell 5 也不行。

我知道 ps 管道可以传 PS-Object,但不会不会兼容文件流吧,目前还没找到说这个问题的,先在这分享一下继续寻找 解决方案。

3496 次点击
所在节点    PowerShell
9 条回复
Tumblr
2020-07-29 13:55:07 +08:00
🤦‍♂️ 在 PowerShell 中,cat 是 Get-Content 的 alias,获取出来的是按行分割的数组;
管道传递的时候,是一个元素一个元素地传递,这样写肯定不行了。
ColinZeb
2020-07-29 13:58:18 +08:00
@Tumblr 不是 cat 的问题,换成 wsl cat 也一样的
ghostwwg
2020-07-29 14:09:34 +08:00
木有问题啊。。。
ghostwwg
2020-07-29 14:09:53 +08:00
indows PowerShell
版权所有 (C) Microsoft Corporation 。保留所有权利。

尝试新的跨平台 PowerShell https://aka.ms/pscore6

PS C:\Users\ghost> cat .\testpage|gzip > aaa.gz
PS C:\Users\ghost> ls .\aaa.gz


目录: C:\Users\ghost


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2020/7/29 14:09 56 aaa.gz


PS C:\Users\ghost>
geelaw
2020-07-29 14:17:36 +08:00
楼主的遇到的问题是多重问题,第一步 cat 就已经错了,因为它会以文本读取文件,而不是复制二进制流。
第二步管道传入 gzip 也错误,因为经过 PowerShell 的外部程序管道都会经过文本的转换。
第三步保存到文件也错误,因为这个操作也会按照文本解读,还会进行编码转换。

正确解法是使用 Start-Process 来重定向,但是这只能解决输入输出都是文件的简单情况。

那么 PowerShell 使用二进制管道的正解是什么呢?这里臭不要脸地推荐我写的 module Use-RawPipeline,专门解决 PowerShell 二进制管道交互问题,且在 Windows 上以性能最佳的方式实现。

GitHub 链接: https://github.com/GeeLaw/PowerShellThingies/tree/master/modules/Use-RawPipeline
博客: https://geelaw.blog/entries/powershell-use-rawpipeline/

@ghostwwg #4 有文件出现不代表文件内容是对的。
ColinZeb
2020-07-29 14:36:52 +08:00
@ghostwwg 打开文件试试。
@geelaw bash 环境里的 cat 支持文本文件和二进制文件重定向到管道,我以为 pwsh 会兼容
LokiSharp
2020-07-29 14:47:39 +08:00
@ColinZeb #6 pwsh 传的是对象,不是文本。。。
geelaw
2020-07-29 21:04:50 +08:00
@ColinZeb #6 bash 不支持“文本重定向”,它对文本没有概念,管道是二进制流。至于 cat,那是一个外部程序,它也不懂“文本”的概念,只是负责把多个文件粘在一起。举个例子,当你 cat 多个用 UTF 编码的文本文件时,结果不会得到统一的编码,也不会删除多余的 BOM 。

PowerShell 没有特别想要兼容其他 shell 的用法,而且管道传输对象本来就和大多数 shell 不兼容。
hez2010
2022-03-05 19:45:19 +08:00
这是一个古老的问题: https://github.com/PowerShell/PowerShell/issues/1908 ,PowerShell 的 > 会把东西转换成文本导致原数据被破坏,只不过因为为了兼容性一直没有进行这个破坏性更改。
另外 PowerShell 的 cat 也是默认转换成字符串数组,要用 Get-Content -AsByteStream xxx 或者 cat -AsByteStream xxx 才能获取到源数据。

不过下一个版本 PowerShell 7.3 应该会给出解决方案。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/694017

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX