如何编写一个系统命令
本文首发于个人博客 Cyy’s Blog
转载请注明出处 https://cyyjs.top/blog/5f689b5196a836000da288fd
作为前端开发,安装npm
包时,我们经常会发现,有些包,会在我们系统中安装一些命令行可执行的命令,如vue-cli
,bable-cli
等等,那么这些命令是如何实现的呢?
# package.json中的bin
以vue-cli为例,我们打开GitHub
,查看packages/@vue/cli
目录下的package.json
文件:
{
"name": "@vue/cli",
"version": "4.5.6",
"description": "Command line interface for rapid Vue.js development",
"bin": {
"vue": "bin/vue.js"
},
"types": "types/index.d.ts",
...
}
会发现,里面有一个bin
字段,这个字段的作用是什么呢?
npm
官方文档中有介绍:
该字段的作用是用来安装npm
的可执行文件,其中bin
字段中的key
如这里的vue
就是命令的名字,对应的值就是具体执行的文件。安装的时候,npm
会创建一个软连接到prefix/bin
目录下进行全局安装,类似于快捷方式
,如果是局部安装,会链接到./node_modules/.bin/
目录下。
如果命令名和包名一样,也可以用字符串的形式,如
{ bin: "bin/vue.js" }
如上vue-cli
全局安装成功后,就就可以在系统/usr/local/bin/
目录下找到一个命名为vue
的如链接。如果vue-cli
是通过yarn
全局安装的话,它指向的具体目录应该为/Users/user/.config/yarn/global/node_modules/@vue/cli/bin/vue.js
。
# 可执行文件
我们打开bin/vue.js
文件,会发现它与普通的js
文件有一些不太一样:文件第一行多了如下代码:
#!/usr/bin/env node
这段代码是什么意思呢?
这种写法是创造Unix
的人搞出来的,沿用至今,意思是用#!
指定脚本的解释器,就是指定运行当前文件的命令是什么。
比如:
#!/bin/bash
echo 'hello word!'
告诉系统用bash
来执行这个文件。
我们通过which node
可以看到我们node
命令所在的位置:/usr/local/bin/node
那么为什么vue
中使用的是#!/usr/bin/env node
而不是#!/usr/local/bin/node
?
这是出于系统兼容性考虑,为了防止操作系统用户没有将node
装在默认的/usr/local/bin
路径里,当系统看到这一行的时候,首先会到env设置里查找node
的安装路径,再调用对应路径下的解释器程序完成操作。
# 如何直接编写一个命令
通过上面的了解,我们可能会想,通过#!/usr/bin/env node
编写一个js
文件,能否直接运行呢?我们可以编写一个js文件来试一试:
test.js
:
#!/usr/bin/env node
console.log('hello word!')
我们知道在命令行中执行的命令都是全局安装的,或者路径是在环境变量中的,我们可以为此文件建立一个软连到对应的环境变量所在的目录中去,如下:
ln -s ./test.js /usr/bin/test
然后直接执行命令test
发现报错了,没有权限:
permission denied: test
因为创建的文件,一般是没有可执行权限的,我们为文件添加执行权限:
chmod +x test.js
然后再次执行,不出意外可以看到能够正确输出hello word!
了。
此时我们已经成功创建了一个全局的命令。
# 扩展
既然我们知道#!/usr/bin/env node
指定了文件解释器的类型为node
,就可以直接用node
来执行文件内的代码,那么如果使用别的语言是否可以呢,考虑以下代码:
修test.js
文件的内容,后缀什么的无所谓,也可以没有后缀
#!/usr/bin/env python
print('Hello python!')
然后在控制台输入test
命令,发现正常输出了Hello python!
✨
