Windows命令行和Linux差在哪里?
看到大家都很嫌弃Windows自带的命令行工具(命令提示符和PowerShell),那么它们到底和Linux的命令行差在哪里?
差在哪?差在软体生态啊。
拿操作系统为例的话,你用的不是操作系统,你用的是操作系统之上的各种app。一个操作系统之上有各种优秀的app,那么哪怕这个操作系统设计得很烂,优化得很差,也是会有很多人用的,至于它优化差的问题可以靠疯狂堆硬体解决,我说的自然就是____系统。
说回到命令行也是一样,用户使用的,其实不是命令行的shell本身,也不是终端模拟器程序,而是,大量的基于命令行的app,以及这些app之间的搭配。
大量的基于命令行的那些Linux app形成了肌肉记忆,旁人只道我在命令行运指如飞,可不知道要达到这种状态是经过了多长时间的历史积淀。而Linux命令行的应用生态,丰富得让你可以实现操作系统中需要做到的几乎所有事情。
Windows下,没有这成百上千的基于命令行的app,没有这些让人已经习惯成自然的app,没法使用就像吃饭喝水一般自然的这些命令行app,自然,Windows命令行就没办法好用:因为基于Windows命令行的软体生态太贫瘠了。
这,其实与PowerShell还是bash并没有什么直接关系。
--
补充:有的人认为ps在设计理念上全方位超越bash。这句话粗看起来似乎有道理,然而,一个shell它首先是一个命令行,其次才是个批处理编程语言。
使用更先进编程理念的shell从来就没能在普及层面战胜目前的shell,因为他们忽略了,手工输入的方便快捷才是shell的第一需求。
Windows 在很长一段时间内,自带的终端模拟器都一言难尽:难以配置,默认情况下很丑陋,复制粘贴的逻辑很别扭等等,直到 Windows Terminal 出来才缓解了这个状况,但 Windows Terminal 到目前还不是默认的终端模拟器,单纯这个原因就让 Windows 的终端体验下降很多。
另一个问题是补全问题。虽然现在 PowerShell 支持的补全功能并不弱,但糟糕的是,没有几个第三方工具适配了 ps 补全功能,对于没有适配的工具,补全工具基本只能用来补全路径,而 bash 上补全适配状态要好的多。而且,Linux 上命令补全通常是渐进式的,每次按下 TAB 都会补全到最长的公共前缀上,并展示可能的命令,而到了 Windows 上 TAB 补全就变成了在输入处遍历可能的补全列表,按过头了还需要再循环一圈,想回退到按 TAB 前的状态还只能手动退格……也许是我习惯问题,但我觉得 Linux 上默认的的补全逻辑远远比 Windows 上更加易用。
至于 Shell 方面,cmd 更是一言难尽,我也不多说了。PowerShell 设计上很不错,但我并不认为它适合作为 Shell 来使用,而是更适合用来写脚本,冗长的命令与选项加上 Windows 的补全逻辑作为 shell 用起来简直是灾难,哪怕 wsl 里运行 pwsh 都比 Windows 上直接运行的 PowerShell 要易用的多的多。另外 PowerShell 启动速度也要慢于 cmd 慢于 bash,这个问题近期倒是改善了不少,但是用起来还是和 bash 挥之即来招之即去的流畅感有所差距。
再就是 Windows 上命令行生态和 Linux 的差距,这是 Windows 重 GUI 轻 CUI 的风格造成的。Windows 上相当一部分 CUI 应用还是移植自 *nix,由此引来的风格差异也是降低 PowerShell 易用性的重要因素之一。
顺带一提,PowerShell 用来写脚本不错,不过我更喜欢 Ammonite 一些:
Ammonite?ammonite.io作为一门语言来说,Ammonite 的功能远强于 PowerShell,因为它支持的是 Scala 的一个超集。与 PowerShell 能利用 .Net 生态类似,Ammonite 也能够利用整个 JVM 生态,它甚至支持从远程 Maven 仓库自由导入 package,譬如想使用阿里云的 OSS SDK,只需要这样:
import $ivy.`com.aliyun.oss:aliyun-sdk-oss:3.9.1`
然后就能导入 SDK 中的类型了:
import com.aliyun.oss.OSSClient
import com.aliyun.oss.model._
更多的功能请参见官网文档。
这个问题需要从至少 3 个不同的方面来看——首先你得把 Shell 和 Terminal 这两个概念分开,然后还要考虑的是围绕命令行界面(CLI)所构建的生态环境。很多人都把他们混在了一起,得出的结论就大不相同甚至截然相反。
Shell 就是真正解释并执行命令的那个程序,比如 cmd/PowerShell/bash,它们各自使用自己的语言,比如 cmd 使用的语言叫 Batch(批处理)。Terminal 是用来显示结果、处理输入输出的那个程序,Windows 上自带的叫 conhost,Linux 不同的桌面环境自带的 Terminal 不同。由于 bash 是大多数 Linux 发行版默认的 shell,下面就都是拿他跟 cmd/PowerShell 作比较了。
从 Shell 语言所提供的功能角度讲,Batch 无疑是这三个当中最弱鸡的,例如没有函数(只能用 CALL 和标签模拟)、没有 switch-case 等等。PowerShell 功能最强,面向对象、并且与 .net 有良好的互操作性,甚至可以嵌入 C# 代码:
$id = get-random
$code = @"
using System;
namespace HelloWorld
{
public class Program$id
{
public static void Main(){
Console.WriteLine("Hello world!");
}
}
}
"@
Add-Type -TypeDefinition $code -Language CSharp
iex "[HelloWorld.Program$id]::Main()"
当然 Bash 也能模拟一下面向对象甚至函数式编程,但这不是语言提供的一等功能。PowerShell 也有一个相当明显的缺点,就是跟 bash 相比太啰唆。
从 Shell 程序所提供的功能角度讲,cmd 仍然是最弱鸡的,例如历史记录无法持久化保存、没有 profile 支持。PowerShell 目前这两点都是支持的。
因此如果有人说 cmd(Batch) 比 bash 差,这完全没有问题。但是要是拿 PowerShell 跟 bash 相比,我认为还是 PS 技高一筹。
下面说一下 Terminal:Windows 自带的那个 conhost 被 Linux 上一众 Terminals 吊打我认为毫无问题,随便就能想得到很多槽点(有一些槽点在 Windows 10 上解决了,但还是很想吐):
- 字体受限
- 颜色受限
- 窗口宽度受限
- 行选择
- 默认是当前语言的编码
- 不支持 ANSI terminal code
- 功能上的缺失,比如标签页、搜索…
- ……
由于 conhost 在兼容性上无法妥协,因此有了新的 Windows Terminal。还有很多其他的第三方 Terminal,比如 ConEmu,不过这些都不是「系统自带」的。因此如果有人说 conhost 难用的一批,请不要反驳并加入他们。
最后是围绕命令行界面所构建的生态。从系统管理与维护的角度讲,其实 Windows 与 Linux 并没有太大差距,比如 Windows ServerCore 就是不带桌面环境的 Windows Server。还有很多程序专门提供了 PowerShell Module 来对软体进行管理,例如 CosmosDB Emulator。
但在其他方面(第三方程序的丰富程度、命令行包管理器等),Linux 无疑要比 Windows 强很多,甚至 bash 不喜欢的话还可以换别的。我认为主要原因在于 Linux 的桌面环境不是必需品,用户用什么桌面环境、甚至有没有桌面环境都不一定,而 Windows API 就实实在在在那,还有相当好的兼容性,图形界面又对普通用户更友好。这样的 API 不用白不用,用了不白用,白用谁不用 _(:з」∠)_
拿一个具体例子来说,就是很多人提到的软体包管理工具 scoop。它的命令行介面就可以凸显出 Windows 的命令行和 Linux 的命令行有多少差距。
例子一、
scoop install 只能用来安装新的包,如果这个包已经存在(即使残缺不全,甚至只有一个空目录),就提示出错,只能先用 scoop uninstall 将其卸载然后重新安装。
比如我安装 curl,在下载过程中 ctrl + c 退出,再安装,就会提示这个错误: