SHELL可执行脚本
写一个 shell 命令行脚本。
echo "Hello World !"
如何运行这个脚本?
sh test001.sh
这还不是一个命令行工具,这里命令行工具是 sh,test001.sh 是这个工具的一个参数。
如何转转换成命令行工具?
#!/bin/bash
echo "Hello World !"
chmod +x test001.sh
以命令行工具的形式执行。
./test001.sh
和平常的命令行工具有点不一样?
重命名成 test001,放入系统路径中,就可以直接用 test001 全局执行命令。
export PATH="/usr/local/opt/ruby/bin:$PATH"
复杂多文件的情况?
test001
|--bin/
|----test001
|--lib/
|----...
export PATH="/path/to/test001/bin:$PATH"
扩展一
cat /etc/shells
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/bin/false
扩展二
#!/usr/bin/env shell
1、兼容性,/usr/bin/env 从系统路径中查找脚本解释器路径
2、/usr/bin/env 有 -S -P 参数,可以指定其他查找路径
#!/usr/bin/env -S -P /custom/search/path:${PATH} bash
NODEJS 可执行脚本
同理
# test002.js
console.log('hello world');
node test002.js
#!/usr/bin/env node
console.log('hello world');
chmod +x test002.js
./test002.js
去扩展名,复杂多文件的情况?
.
├── bin
│ ├── aides
│ ├── aides_application
│ ├── aides_component
│ ├── aides_fwtool
│ ├── enums
│ └── tools
├── jsconfig.json
├── lib
│ ├── application
│ ├── commons
│ ├── component
│ ├── fwtool
│ └── index.js
├── node_modules
| |...
├── package-lock.json
├── package.json
├── src
│ ├── application
│ ├── commons
│ ├── component
│ ├── fwtool
│ └── index.js
├── README.md
└── yarn.lock
扩展一
对 nodejs 命令行工具,不需要手动设置系统路径
{
"name": "test002",
"bin": {
"test002": "path/to/entry\ file"
}
}
npm link
NODEJS 命令行工具开发
获取命令行参数
1、普通方式
在 nodejs 脚本中,通过 process.argv 获取命令行参数,process.argv 是个数组:
#!/usr/bin/env node
console.log('process.argv: ', process.argv);
node test001.js -a -b -c -d 123 --aaa --bbb --ccc --ddd 123 456
process.argv: [ '/usr/local/Cellar/node/11.3.0_1/bin/node',
'/Users/eqielb/Test/test/test001.js',
'-a',
'-b',
'-c',
'-d',
'123',
'--aaa',
'--bbb',
'--ccc',
'--ddd',
'123',
'456' ]
./test001.js -a -b -c -d 123 --aaa --bbb --ccc --ddd 123 456
输出结果是一样的。
2、commander 模块
手动分析管理参数非常麻烦,可以使用 commander
模块
https://www.npmjs.com/package/commander
3、 yargs 模块
https://www.npmjs.com/package/yargs
https://www.npmjs.com/package/minimist
5、模块对比
调用系统其他命令
1、基础模块
可以通过 nodejs 的 child_process 模块,新建子进程执行其他命令
#!/usr/bin/env node
var name = process.argv[2];
var exec = require('child_process').exec;
var child = exec('echo hello ' + name, function(err, stdout, stderr) {
if (err) throw err;
console.log(stdout);
});
2、通用模块
如:安装 shelljs 模块
#!/usr/bin/env node
var name = process.argv[2];
var shell = require("shelljs");
shell.exec("echo hello " + name);
如:安装 execa 模块
const execa = require('execa');
(async () => {
const {stdout} = await execa('echo', ['unicorns']);
console.log(stdout);
})();
模块对比:
3、特定模块
如: 安装 nodegit 模块
var Git = require("nodegit");
Git.Clone("https://github.com/nodegit/nodegit", "./tmp")
.then(function(repo) {
return repo.getCommit("59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5");
})
命令行交互
1、inquirer 包
美化控制台输出
1、chalk、colors 包
2、ora 包、cli-spinners 包
3、blessed-contrib 包
https://github.com/yaronn/blessed-contrib
4、命令行字体 figlet
_ __ ___ ___ __ _ _ _
| '_ _ \ / _ \ / _
|| | | |
| | | | | || (_) || (_| || |_| |
|_| |_| |_| \___/ \__, | \__,_|
|___/
其他事项
1、返回值
根据 Unix 传统,程序执行成功返回 0,否则返回 1 。
if (err) {
process.exit(1);
} else {
process.exit(0);
}
process.exitCode = 1;
process.exit();
扩展一
process.exit 有回调方法
process.on('exit', (code) => {
console.log(About to exit with code: ${</span><span class="cm-variable-2">code</span><span class="cm-string-2">}
);
});
扩展二
一般情况下,不建议直接调用 process.exit() 方法,直接调用会导致异步方法中断。需要手动异常退出的话,可以设置 process.exitCode ,并抛出 uncaught error,让进程根据异常自动退出。
2、重定向
ps aux | grep 'node'
nodejs 中实现这种功能
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(data) {
process.stdout.write(data);
});
3、系统信号
接受系统信号
process.on('SIGINT', function () {
console.log('Got a SIGINT');
process.exit(0);
});
发送系统信号
kill -s SIGINT [process_id]
扩展
这些功能开发不太常用,运维会用到,看公司发布系统的脚本
发布
命令行工具就是一个 npm 包,执行 npm publish 进行发布,npm i 安装后就可以使用。
NODEJS 命令行工具应用举例
1、主机管理
aws、google cloud、aliyun、qcloud 等都支持 oauth 2.0认证,可以命令行下做验证通过命令行管理服务。
2、命令行爬虫
3、自动提交表单