二进制管道, PowerShell 竟还不如 CMD

2021-01-26 21:10:04 +08:00
 orannge

这几天用了下 PowerShell,发现用到二进制管道的地方速度奇慢,例如tar -cf - 1.bin > 1.tgz。测试文件 100M,CMD 敲下命令就出结果了,PowerShell 用了整整三十来秒!就算执行结束了,结果也还是错的。

类似命令还有cat 1.bin > 2.bin,进一步了解之后发现catGet-Content的别名,会以字符串读取文件,> 也不是重定向流,仅仅是 | Out-File 的语法糖。找了一圈,设置编码等等,发现官方并没有等效命令,GitHub 16 年的 issue 现在都没关(PowerShell#1908)?

有个第三方模块说可以解决这个问题,Use-RawPipeline,好的装上,于是命令变成run tar "-cf" "-" 1.bin | out2 1.tgz,虽然不那么直观,参数引号不能忘,速度差了一倍,好歹是能用了。然后这模块加载要 700ms,终端打开都要卡一下,于是设置function load { Import-Module -Name Use-RawPipeline },用到相关命令的时候手动 load 一下。啊这,cmd /c tar -cf - 1.bin > 1.tgz不香吗?

测试用的内存盘,综合下来 WSL2 满速 900M/S,CMD 满速 700M/S,PowerShell 7.1 只有 40M/S,Use-RawPipeline 速度 320M/S 。PowerShell 15-20 倍速度损失,Use-RawPipeline 1 倍速度损失。二进制管道用到的地方还是挺多的,tar/git/curl 等等。

选择 PowerShell 是因为想在 Windows 下用用脚本,毕竟 CMD 实在太难用了。有说 PowerShell 已经跨平台,比 bash 都好用,结果连 CMD 都完全替代不了,哈哈。

5384 次点击
所在节点    Windows
36 条回复
ragnaroks
2021-01-27 10:56:44 +08:00
如果你使用 CSharp 的话,powershell 可以理解为把 CSharp 当作脚本来用

尴尬的是 CSharp 本来就可以当脚本用,而且 VS 比 ISE 不知道高到哪里去了
ragnaroks
2021-01-27 10:59:01 +08:00
powershell 的 curl 是 Invoke-WebRequest 的别名,遇到过一次 Invoke-WebRequest 不正常,后来装系统都直接把 powershell.exe 链接到 cmd.exe
jorneyr
2021-01-27 13:31:06 +08:00
Powershell 里执行 java -jar -Dfile.encoding=UTF-8 xx.jar 报错,CMD 里没问题,不用 -Dfile.encoding 就没事。
AndyAO
2021-01-27 14:24:58 +08:00
#20 #18

现在已经很少有人会用 ISE 了,你应该是有段时间没有用 PowerShell 了.
目前 PowerShell 已经更新到 PowerShell 7,依托于.Net Core+Visual Studio Code,实现了跨平台.ISE 已经停止更新了.

目前新 PowerShell 的开发一直都很活跃,没有停下的迹象,开发团队的博客经常会更新,GitHub 上面的仓库也很活跃,这说明有很多人在使用它,而且微软看好它的未来.

C#不符合'脚本语言'的定义(维基百科上的,可以说是大多数人的看法),它是静态类型的,有冗长的依法规则,执行之前要先进行编译,而且它的执行速度和 C 很接近.

这些都说明 C#不是什么脚本语言.

所以你的看法令人感到困惑.
AndyAO
2021-01-27 14:29:22 +08:00
#20 不小心点错了,刚刚的回复不是给你的.
AndyAO
2021-01-27 14:39:24 +08:00
那是因为你不懂 PowerShell 的语法
后面几位的回复和楼主基本上都是相同的

先假设 PowerShell 和之前的其他 Shell 用法是相同的
然后按照那个方法使用,发现用不了之后就感到有点失望

PowerShell 这是个新工具,使用它不是自然而然的,是需要一些学习成本的

而其实这个问题去谷歌一下就马上能找到答案,可能大多数人真的不太喜欢离开自己的舒适区吧

@jorneyr #20
orannge
2021-01-27 19:38:58 +08:00
@AndyAO PowerShell 在 Windows 下大多数情况还是挺好用的,跟 C#深度结合,够现代化。我开始以为 PowerShell 是 CMD 的替代品,就像 bash/zsh 之于 Linux,任选其一即可,不存在无法替代的情况。合适的工具干合适的事,用 PowerShell 就跟随它的设计理念吧。

还有一点是如果开发一个全平台工具,要考虑到用户可能在 PowerShell 执行,一些用法并不通用。如果是自用脚本,不考虑 PowerShell,如楼上所说,也还有 GitSCM/Cygwin/coreutils 可供选择。
jorneyr
2021-01-28 09:07:15 +08:00
@AndyAO 没有专门学习过 Powershell 的语法,但是 java -jar -Dfile.encoding=UTF-8 xx.jar 这个命令在 CMD,Linux,Mac 下都没问题,在 Powershell 有问题,你说我要看啥语法?
AndyAO
2021-01-28 09:17:05 +08:00
@jorneyr #25
去谷歌搜一下就明白的事情了,你非要让我给你粘贴上来,不学习就是这么可怕
基本概念都没搞清楚
AndyAO
2021-01-28 09:31:05 +08:00
@orannge #23

基本同意你的观点,不过我想补充一下 :

你刚才说的那个场景,如果只是暂时用用,那么可以直接使用 CMD 等其他方法绕开,坏处就是体验有割裂,突然用不了 PowerShell 上的各种便利功能

如果经常要用,想要让所有的操作都能和 Cmdlet 有类似体验,那么其实有途径封装成 Cmdlet

比如说 PowerShell 最近就出了专门的工具来将这个封装工作更加的自动化

[Announcing PowerShell Crescendo Preview.1 | PowerShell]( https://devblogs.microsoft.com/powershell/announcing-powershell-crescendo-preview-1/)


关键是看谁用,如果真心的想使用 PowerShell,发现不懂的就去学,那么肯定不会将二进制数据直接传到管道里面去

因为管道里面默认是对象,要不就是字符串,要不就是别的对象,二进制数据也是要封装在对象里面的,这个只要是学过基本概念的就熟悉

开发跨平台 CLI 工具,在 PowerShell 遇到的问题就是 : 那些没有学过 PowerShell 基本概念的人,要求 PowerShell 和其他基于文本的 Shell,完全相同的人,使用上的兼容性会出问题,如果是经常使用 PowerShell,那些问题基本上都是可以绕过去的,不是什么大事,微软不傻,不可能把兼容性做得如此烂,以至于各种工具都用不了,如上所述,关于兼容性问题改进,一直都在持续
AndyAO
2021-01-28 09:56:46 +08:00
@jorneyr #25
算了,我也不想说半截话,就把你那个问题给答完了

你那个问题在谷歌上这么搜索,首个结果就会有答案`PowerShell "-Dfile.encoding=UTF-8"`

powershell - Specify the default file encoding in Java - Stack Overflow
https://stackoverflow.com/questions/33393001/specify-the-default-file-encoding-in-java

所以说这就是个动动手指的问题啊,除非你不能翻墙,谷歌用不了,否则我对你不理解这个问题,感到有点难以置信

除了上面说的方法,还有一种方法是加入`--%`,这个在与调用相关的文档上就有,所以说你哪怕有一点心思想学一下 PowerShell,那么你就不会犯这个错误

那么总结下来就是

`java -jar -Dfile.encoding=UTF-8 JavaHelloWorld.jar` 语法错误

`java -jar "-Dfile.encoding=UTF-8" JavaHelloWorld.jar` 语法正确

`java -jar -Dfile.encoding=UTF-8 JavaHelloWorld.jar` 语法正确

这个你仔细观察一下从控制台的高亮上就能够看出来

![]( https://cdn.jsdelivr.net/gh/Andy-AO/GitHubPictureBed/img/20210128095422.png)

我就不多说了,希望对你有点帮助
AndyAO
2021-01-28 10:12:23 +08:00
对于上面那个问题再补充一些

在 PowerShell 上一切都是对象,包括传递参数这个过程,在其他文本 Shell 中,后面打的所有字都是字符串,但在 PowerShell 中后面的东西都是参数列表,本质上也是对象是需要经过解析之后再来调用的,而`-`是参数列表中参数名字的语法.

所以错误提示为`Error: Unable to access jarfile .encoding=UTF-8`,`-Dfile`被 PowerShell 解释成参数的名字,所以就更没传递进去.

面向对象之后是很有好处的,尤其是命令比较复杂的时候,直接可以在外面写个列表,然后直接传进去,根本就不需要折腾字符串了.

当然,如果你有个早就写好或者从网上直接复制粘贴的巨长无比的可读线几乎没有的字符串命令,那么在上面说了最好的方法就是直接用`--%`,告诉 PowerShell 停止使用面向对象的思维来考虑问题,直接当所有东西都是字符串,那么问题就迎刃而解了

参考资料:
about_Command_Syntax
about_Parsing
jorneyr
2021-01-28 11:07:49 +08:00
@AndyAO 你没明白,不是说 Powershell 解决不了,而是这么用大家都没问题,就你有问题,你说是谁的问题?所以不合群就放弃了啊!
AndyAO
2021-01-28 12:31:48 +08:00
@jorneyr #30
原来你是这个意思.
那我感到不再困惑了!

还是像之前说的那样,大多数人都不愿意走出自己的舒适区,毕竟这样很累,风险很高.

更新更好的东西往往和之前的不合群.
终于买了个汽车,然后一拍方向盘,大喊'驾'
结果发现汽车岿然不动
发誓不再用汽车了,汽车真是个不合群的东西,和马和驴都不一样
AndyAO
2021-01-31 14:34:05 +08:00
C# 和 F# 都有了自己的 Script
好像获得这个支持不长时间
我刚知道啊
所以说上面的朋友说 C#也能当做脚本用,的确是可以的
目前我还没用上,不知道和 PowerShell 有什么区别
但可以肯定的是 PowerShell 微软仍然是大力支持的,发展很快
我想就算是 C#的某些语法被改变,支持类似脚本的模式了
那么 Shell,以及依托于 Shell 的脚本语言仍然是必要的
AndyAO
2021-02-13 14:04:36 +08:00
还有就是 , 楼上朋友说 C# 能替代 PowerShell 的 , 所以显得比较鸡肋.

这里补充更多的信息 , 纵然 C# 现在已经支持了 REPL , 使用起来是远远不及脚本语言的.

因为那些琐碎的语法仍然大量的存在 , 根本没办法,好好的去专注的进行 REPL.

所以说 PowerShell 的优势是 C# 很难替代的 , 在 JVM 平台上也有类似的东西,而且非常火 , 那就是 Groovy 和 Scala , 就更不用说在 JDK 9 中 , 甲骨文官方引入了 JShell , 从而让 Java 有类官方的 REPL.

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

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

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

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

© 2021 V2EX