跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 二进制管道, PowerShell 竟还不如 CMD
未分類
4 2 月 2021

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

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

資深大佬 : orannge 8

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

类似命令还有cat 1.bin > 2.bin,进一步了解之后发现cat是Get-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 都完全替代不了,哈哈。

大佬有話說 (34)

  • 資深大佬 : Jirajine

    慢可能是因为二进制数据先被解析成 string 了,并且对无效字符可能进行替换。你会发现最终产生出来的文件已经面目全非。

  • 資深大佬 : nightwitch

    裸 powershell 冷启动也要几百毫秒
    稍微加点 oh-my-posh 再加点其他模块,冷启动时间慢到不能忍受.

  • 資深大佬 : leido

    powershell 的管道不是原始字节流 , 包装成 .net 对象 的

  • 資深大佬 : codehz

    其实说到底就是 windows 的坑,0202 年还在折腾编码问题,以至于不能 utf-8 走天下。。。如果假设所有终端程序都用 utf-8,就不会做出先解析输出内容的设计决策。。。

  • 資深大佬 : leido

    看了你的需求, 建议试试 wsl
    https://docs.microsoft.com/en-us/windows/wsl/install-win10

  • 資深大佬 : AndyAO

    Out-File 处理的本来就是字符串,不是二进制数据,这个在文档上有,所以只要看过文档就应该立即能明白.

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-file?view=powershell-7.1

    没有什么东西是完美的,这是 PowerShell 取舍,他认为这么做在大多数情况下效率都会更高.

    如果你认为 PowerShell 这个判断是错误的,可以用其他方式来实现.例如,你可以直接在 PowerShell 中调用 CMD 命令.

    学习使用 PowerShell,最好是以 PowerShell 的思维来思考,而不是要求 PowerShell 迁就你之前的习惯.

  • 資深大佬 : by73

    跟 pwsh 的设计有点关系,pwsh 管道传递的是 object,基本所有操作都是基于 object 和字符串的,某些情况下用着会比较舒服(例如获取一些信息,可以直接用 select,不需要写正则去 grep 等),而且 pwsh 最大的一个特性是跟 csharp 的代码结合的很好,虽然我不怎么用 = =

    P.S. 我也要吐槽以下 pwsh,重定向总喜欢给我输出 UTF16 。。

  • 資深大佬 : AndyAO

    tar/git/curl 这些东西,都是类 Unix 平台上的工具,可以说是量身打造的.

    在 PowerShell 上来使用它们,效率不如原来的平台上高几乎是必然的.

    作为后来者这个很吃亏,如果有人在 C#上写了完全兼容 Git 的工具,那么效率就会很高,其他工具也是如此.

  • 主 資深大佬 : orannge

    @AndyAO 这么说都是生态问题,类似这种命令本就是留给 CMD 来处理的

  • 資深大佬 : AndyAO

    @orannge #9
    1. 是否是生态的问题

    在第 8 上,我的意思是这样的,如果有类似的工具是用 C#写的,那么用 Unix 上的的使用方式反而是蹩脚的.

    之所以感觉很蹩脚很不好用,是因为你在跨平台使用这些工具,例如 git,在 Windows 跑起来就需要很多支持工具,有兼容性问题是难免的.

    我不确定 C#上是否已经有很好的工具能满足你那个操作需求,如果能的话,那么你可以更改自己的习惯,如果没有这样的好工具,那就是生态问题.

    这个生态问题可能会很长时间都解决不了,因为新的工具要想替代老的,除非好很多,否则的话一般是不会替代的,会将就着用,很长很长时间.

    2. 是不是本来就留给 CMD 处理的

    坦白讲,我也不清楚他们团队的想法,但让我想到了此前遇到的问题,那就是建立软硬链接,必须要调 CMD,否则就要用 Win32Api.

    你现在去 StackOverFlow 还能看到这样的问题,那些被标记为√的,都是这个方案.

    但是在 PowerShell V5 后就内置了,为 New-Item 增加了新的参数,支持所有链接.

    也许谁都想做尽善尽美的东西,能力有限,还是要分个轻重缓急的吧.

  • 資深大佬 : favourstreet

    所以我在 powershell 里常用的一个命令是 cmd.exe /c “……”

  • 資深大佬 : rekulas

    win 平台一直用 gitscm 基本没遇到什么问题 而且跟 linux 工具包一致 通畅

  • 資深大佬 : Tumblr

    感觉就是敲了几个命令就来妄加评判的无知之谈。。。
    通篇在说读写速率的问题,没看到哪条佐证主观点,甚至主都貌似不知道 PowerShell 的管道传输的是对象。。。

    力气不够怪刀重,功夫不精怨招轻。。。

  • 資深大佬 : iamwho

    https://github.com/uutils/coreutils

    试试这个

  • 資深大佬 : UnknownSky

    emm,关闭 WD 试试,日常遇到 Powershell 命令慢的要死,把 Windows Defender 关了就好了

  • 資深大佬 : ETiV

    LZ 会写 bash 脚本的话,可以装个 Cygwin 工具集合
    我既不会 Power Shell 又不想写 bat
    在 Windows 上基本都是用的 Cygwin+bash 了

  • 資深大佬 : lxilu

    @codehz 这应是设计为`了对象管道

  • 資深大佬 : bthulu

    @AndyAO 诺基亚也是这样想的, 绝不能迁就用户的习惯

  • 資深大佬 : AndyAO

    @bthulu #16 苹果和特斯拉也是

  • 資深大佬 : AndyAO

    看到前面很多人提到了 PowerShell 模块加载的速度问题.
    其实模块没有必要提前进行加载,除非直接对全局进行了更改,比如说 posh-git.
    在 PowerShell 中,只要你的模块是安装在指定目录中的,可以在首次使用的时候自动加载.
    很多人可能不清楚这点,所以就把很多的模块在最初全部导入了,那速度肯定快不了.
    不过,如果这些模块确定要使用,那么提前导入还是有好处的,加快了使用时候的速度和提高了一致性.

  • 資深大佬 : ragnaroks

    如果你使用 CSharp 的话,powershell 可以理解为把 CSharp 当作脚本来用

    尴尬的是 CSharp 本来就可以当脚本用,而且 VS 比 ISE 不知道高到哪里去了

  • 資深大佬 : ragnaroks

    powershell 的 curl 是 Invoke-WebRequest 的别名,遇到过一次 Invoke-WebRequest 不正常,后来装系统都直接把 powershell.exe 链接到 cmd.exe

  • 資深大佬 : jorneyr

    Powershell 里执行 java -jar -Dfile.encoding=UTF-8 xx.jar 报错,CMD 里没问题,不用 -Dfile.encoding 就没事。

  • 資深大佬 : AndyAO

    #20 #18

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

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

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

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

    所以你的看法令人感到困惑.

  • 資深大佬 : AndyAO

    #20 不小心点错了,刚刚的回复不是给你的.

  • 資深大佬 : AndyAO

    那是因为你不懂 PowerShell 的语法
    后面几位的回复和主基本上都是相同的

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

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

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

    @jorneyr #20

  • 主 資深大佬 : orannge

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

    还有一点是如果开发一个全平台工具,要考虑到用户可能在 PowerShell 执行,一些用法并不通用。如果是自用脚本,不考虑 PowerShell,如上所说,也还有 GitSCM/Cygwin/coreutils 可供选择。

  • 資深大佬 : jorneyr

    @AndyAO 没有专门学习过 Powershell 的语法,但是 java -jar -Dfile.encoding=UTF-8 xx.jar 这个命令在 CMD,Linux,Mac 下都没问题,在 Powershell 有问题,你说我要看啥语法?

  • 資深大佬 : AndyAO

    @jorneyr #25
    去谷歌搜一下就明白的事情了,你非要让我给你粘贴上来,不学习就是这么可怕
    基本概念都没搞清楚

  • 資深大佬 : AndyAO

    @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

    @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

    对于上面那个问题再补充一些

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

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

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

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

    参考资料:
    about_Command_Syntax
    about_Parsing

  • 資深大佬 : jorneyr

    @AndyAO 你没明白,不是说 Powershell 解决不了,而是这么用大家都没问题,就你有问题,你说是谁的问题?所以不合群就放弃了啊!

  • 資深大佬 : AndyAO

    @jorneyr #30
    原来你是这个意思.
    那我感到不再困惑了!

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

    更新更好的东西往往和之前的不合群.
    终于买了个汽车,然后一拍方向盘,大喊’驾’
    结果发现汽车岿然不动
    发誓不再用汽车了,汽车真是个不合群的东西,和马和驴都不一样

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具