一、前言
在日常工作中,我们几乎每天都会用到类似npm run xxx
、cd xx
、cls
这样的终端命令,如果你是在linux或者mac上,还可能会使用ls
、clear
这样的命令。
在使用vscode
的打开终端工具的时候,我们可以选择是以cmd
还是以powerShell
的姿势打开终端,如果玩的🌹一点还可以看到git bash
这样的选项。
那么你是否和我一样好奇过一个问题,他们到底都是啥?为啥有的时候在cmd可以运行的命令在powerShell上就不行?为什么要做这样的区分?
和大家一样,我很早就有这个疑问了?但一直在待办里面吃灰,不过今天我们一起来把它搞明白!
二、还得从操作系统讲起
1.内核与外壳
如果各位朋友有时间可以看看我之前的拙作《我一个做前端的,要了解操作系统?》,当然没时间也没关系,这里面其实就讲了一个核心的点,对于现代操作系统都是由内核
和外壳
组成的,内核负责调度、管理内存、操作硬件、对外暴露接口等,做的事情比较多,而外壳就负责与外界进行交互。
打个比方内核就好像是阿里的数以万计的工程师负责写代码,做产品。而外壳就是马老板,对外猛吹牛逼,负责与外界沟通,具体的事情程序员帮助他去实现。
而这个外壳我们亲切的称其为shell
不过分吧!
所以重点来了伙伴们:shell就是操作系统内核与外界沟通的桥梁,不过shell只是一个概念而非一个具体的产品!
既然有概念那么就有具体对应的实现,针对不同的操作系统就有会有不同的实现,并且即便对于同一种操作系统,也都会有不同的实现。
2.shell脚本
在介绍不同的实现之前,我们先聊聊shell脚本,shell与内核进行沟通时,是通过很多不同的命令的,shell通过解析这些命令从而交给内核,内核再交给cpu去执行;而这些个命令的集合就是构成了一种语言,他们也可以有条件语句、循环、变量等概念,因此他们是图灵完备的。如果要深入学习这个脚本语言,这里推荐阮一峰老师的《Bash脚本教程》;我们在使用husky的过程中,可以看到过.sh
后缀的文件,其实就是shell脚本,可以被终端shell直接解析执行。
所以从功能的角度来讲,shell是一个内核与外界沟通的桥梁;从语言的角度来讲,shell是一个shell脚本运行的环境,就像浏览器之于js、jvm之于java一样。但是不同操作系统的shell的实现是不一样的,这就是为什么不同操作系统的终端命令有很大的不一样。例如查看当前位置的目录在linux和mac里面是ls
,在windows中是dir
。
上面讲到的这个大家也许都知道,但是大家是否好奇过一个问题,为啥npm、yarn、rollup、webpack这些命令不管在什么操作系统上都是一样的,使用上不存在区别。
在揭晓答案之前,我们先来看看终端运行命令的过程!
当shell在解析一个命令之前,会先看该命令是否是当前shell的内置的命令,如果是则直接运行,如果不是则优先看系统环境变量所指的目录中有没有该命令的实现,如果有则直接执行,如果没有则再看用户环境变量所指的目录中是否有该命令的实现,如果有则直接执行,如果没有则报错!就会出现我们经常看到的这个错误!
当我们知道了上面的过程就可以推测到,npm并不是一个内部命令,因为在没有node之前,在运行npm的时候,会直接报错。在mac上终端中输入which npm
,就可以看到npm的执行目录,然后在进入该目录,几乎可以查看所有的外部命令的实现。如下图所示:
我们查看一下其中npm是怎么实现的:
再看一下tsc(编译typescript的终端命令)是怎么实现的:
发现他们都有一个共同点,那就是都有这样一段代码#!/usr/bin/env node
,而其他的内容其实就是javascript。以上的实验虽说都是mac举例,但是windows的同学也不用担心,我们所想说明的一切,其实就是下面这样一个结论:
#!/usr/bin/env node
的作用是告诉当前解析器,在解析我的时候,请用node的环境来对于进行解析并执行,换句话说#!/usr/bin/env node
之后的js内容都是在node环境下解析并执行的。所以说几乎所有的由npm下载下来的包所产生的终端命令都是在node环境下运行的js脚本而已。而要知道node本就是跨平台的,在我们安装时我们可以选择是下载什么属于什么平台的node。
我们下载什么平台的node版本,该node版本就会把js脚本解释编译成为这个平台能够认识的机器码交给cpu执行,所以像类似npm
、yarn
、rollup
、tsc
这些命令可以执行实际上是依赖于node,能够跨平台也是因为node可以跨平台。了解完这个,你是否对终端执行命令有更深的了解呢?下面我们就来聊些轻松的了!
对于不同操作系统的shell都有不同的实现,下面我们就分阵营唠唠!
三、linux&mac
我们都知道linux和mac的终端命令几乎是一样的,因为macOS和linux都是基于unix的开发出来的。
历史上,主要的 Shell 有下面这些。
- Bourne Shell(sh)
- Bourne Again shell(bash)
- C Shell(csh)
- TENEX C Shell(tcsh)
- Korn shell(ksh)
- Z Shell(zsh)
- Friendly Interactive Shell(fish)
感兴趣的同学可以看看这篇shell进化史
下面的命令可以查看当前设备的默认 shell(mac和linux)。
$ echo $SHELL
/bin/zsh
例如我的mac默认的shell就是zsh,我的云服务器默认使用的则是bash。
下面的命令可以查看当前安装的所有 shell。
$ cat /etc/shells
三、windows
windows系统的shell有以下具体的实现
- cmd
- powershell
- gitbash
想要了解windows命令行历史的同学可以看看这个,其中需要说明一下,gitbash是一个基于git的命令行环境,它为windows用户提供了一个类似于linux终端的界面,用于在windows上执行git命令和其他shell命令。它还提供了可以在windows上运行的bash,使得用户可以使用unix命令。
其中大家有的时候可能会发现在cmd上可以运行的命令但是在powershell不能运行,从而对powershell就敬而远之,其实这是因为,PowerShell 中设计了一个叫做执行策略(Execution Policy)的东西。我们可以在不同的应用场景中设置不同的策略来防止恶意脚本的执行。因此这属于权限的问题,可以通过增加权限解决。
//运行powershell(管理员身份)
set-ExecutionPolicy RemoteSigned
四、总结
最后我点一下题,我们在看到题目中这些眼花缭乱的概念的时候,可能会有些不知所措,但是其实他们都是一个东西,我们用一个例子来加深一下印象。
你的女朋友小美想要让你给她买部手机,手机
(shell)只是一个概念,不是具体的产品,那到底是买什么品牌的手机呢?如果你恰好兜里有钱,可以选择给她iphone13
(bash),但她觉得不够酷,就想要最新版的iphone14pro
(zsh)。但是你转念一想,明年娶她彩礼还得30万呢!这不得省着花呀,于是你说服她一定要买国产手机,支持国货,要不买小米
吧(cmd),她说不行,国货怎么着也要买华为
(powershell)呀,你前两天看了看华为发布的手机,最少也得5到6k了,你冒起了冷汗!还好你口才好,最后你一顿忽悠,你们决定买oppo
智能手机(gitbash);
五、资源
更多精彩内容,欢迎访问我的个人网站 new-story.cn
我的近期好文: