详解Node.js 命令行程序开发教程


Posted in Javascript onJune 07, 2017

一种编程语言是否易用,很大程度上,取决于开发命令行程序的能力。

Node.js 作为目前最热门的开发工具之一,怎样使用它开发命令行程序,是 Web 开发者应该掌握的技能。

下面就是我在它的基础上扩展的教程,应该是目前最好的解决方案了。

一、可执行脚本

我们从最简单的讲起。

首先,使用 JavaScript 语言,写一个可执行脚本 hello 。

#!/usr/bin/env node
console.log('hello world');

然后,修改 hello 的权限。

$ chmod 755 hello

现在,hello 就可以执行了。

$ ./hello
hello world

如果想把 hello 前面的路径去除,可以将 hello 的路径加入环境变量 PATH。但是,另一种更好的做法,是在当前目录下新建 package.json ,写入下面的内容。

{
 "name": "hello",
 "bin": {
  "hello": "hello"
 }
}

然后执行 npm link 命令。

$ npm link

现在再执行 hello ,就不用输入路径了。

$ hello
hello world

二、命令行参数的原始写法

命令行参数可以用系统变量 process.argv 获取。

下面是一个脚本 hello 。

#!/usr/bin/env node
console.log('hello ', process.argv[2]);

执行时,直接在脚本文件后面,加上参数即可。

$ ./hello tom
hello tom

上面代码中,实际上执行的是 node ./hello tom ,对应的 process.argv 是 ['node', '/path/to/hello', 'tom'] 。

三、新建进程

脚本可以通过 child_process 模块新建子进程,从而执行 Unix 系统命令。

#!/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);
});

用法如下。

$ ./hello tom
hello tom

四、shelljs 模块

shelljs 模块重新包装了 child_process,调用系统命令更加方便。它需要安装后使用。

npm install --save shelljs

然后,改写脚本。

#!/usr/bin/env node
var name = process.argv[2];
var shell = require("shelljs");

shell.exec("echo hello " + name);

上面代码是 shelljs 的本地模式,即通过 exec 方法执行 shell 命令。此外还有全局模式,允许直接在脚本中写 shell 命令。

require('shelljs/global');

if (!which('git')) {
 echo('Sorry, this script requires git');
 exit(1);
}

mkdir('-p', 'out/Release');
cp('-R', 'stuff/*', 'out/Release');

cd('lib');
ls('*.js').forEach(function(file) {
 sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
 sed('-i', /.*REMOVE_THIS_LINE.*\n/, '', file);
 sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file);
});
cd('..');

if (exec('git commit -am "Auto-commit"').code !== 0) {
 echo('Error: Git commit failed');
 exit(1);
}

五、yargs 模块

shelljs 只解决了如何调用 shell 命令,而 yargs 模块能够解决如何处理命令行参数。它也需要安装。

$ npm install --save yargs

yargs 模块提供 argv 对象,用来读取命令行参数。请看改写后的 hello 。

#!/usr/bin/env node
var argv = require('yargs').argv;

console.log('hello ', argv.name);

使用时,下面两种用法都可以。

$ hello --name=tom
hello tom

$ hello --name tom
hello tom

也就是说,process.argv 的原始返回值如下。

$ node hello --name=tom
[ 'node',
 '/path/to/myscript.js',
 '--name=tom' ]

yargs 可以上面的结果改为一个对象,每个参数项就是一个键值对。

var argv = require('yargs').argv;

// $ node hello --name=tom
// argv = {
//  name: tom
// };

如果将 argv.name 改成 argv.n,就可以使用一个字母的短参数形式了。

$ hello -n tom
hello tom

可以使用 alias 方法,指定 name 是 n 的别名。

#!/usr/bin/env node
var argv = require('yargs')
 .alias('n', 'name')
 .argv;

console.log('hello ', argv.n);

这样一来,短参数和长参数就都可以使用了。

$ hello -n tom
hello tom
$ hello --name tom
hello tom

argv 对象有一个下划线(_)属性,可以获取非连词线开头的参数。

#!/usr/bin/env node
var argv = require('yargs').argv;

console.log('hello ', argv.n);
console.log(argv._);

用法如下。

$ hello A -n tom B C
hello tom
[ 'A', 'B', 'C' ]

六、命令行参数的配置

yargs 模块还提供3个方法,用来配置命令行参数。

  1. demand:是否必选
  2. default:默认值
  3. describe:提示
#!/usr/bin/env node
var argv = require('yargs')
 .demand(['n'])
 .default({n: 'tom'})
 .describe({n: 'your name'})
 .argv;

console.log('hello ', argv.n);

上面代码指定 n 参数不可省略,默认值为 tom,并给出一行提示。

options 方法允许将所有这些配置写进一个对象。

#!/usr/bin/env node
var argv = require('yargs')
 .option('n', {
  alias : 'name',
  demand: true,
  default: 'tom',
  describe: 'your name',
  type: 'string'
 })
 .argv;

console.log('hello ', argv.n);

有时,某些参数不需要值,只起到一个开关作用,这时可以用 boolean 方法指定这些参数返回布尔值。

#!/usr/bin/env node
var argv = require('yargs')
 .boolean(['n'])
 .argv;

console.log('hello ', argv.n);

上面代码中,参数 n 总是返回一个布尔值,用法如下。

$ hello
hello false
$ hello -n
hello true
$ hello -n tom
hello true

boolean 方法也可以作为属性,写入 option 对象。

#!/usr/bin/env node
var argv = require('yargs')
 .option('n', {
  boolean: true
 })
 .argv;

console.log('hello ', argv.n);

七、帮助信息

yargs 模块提供以下方法,生成帮助信息。

  1. usage:用法格式
  2. example:提供例子
  3. help:显示帮助信息
  4. epilog:出现在帮助信息的结尾
#!/usr/bin/env node
var argv = require('yargs')
 .option('f', {
  alias : 'name',
  demand: true,
  default: 'tom',
  describe: 'your name',
  type: 'string'
 })
 .usage('Usage: hello [options]')
 .example('hello -n tom', 'say hello to Tom')
 .help('h')
 .alias('h', 'help')
 .epilog('copyright 2015')
 .argv;

console.log('hello ', argv.n);

执行结果如下。

$ hello -h

Usage: hello [options]

Options:
 -f, --name your name [string] [required] [default: "tom"]
 -h, --help Show help [boolean]

Examples:
 hello -n tom say hello to Tom

copyright 2015

八、子命令

yargs 模块还允许通过 command 方法,设置 Git 风格的子命令。

#!/usr/bin/env node
var argv = require('yargs')
 .command("morning", "good morning", function (yargs) {
  console.log("Good Morning");
 })
 .command("evening", "good evening", function (yargs) {
  console.log("Good Evening");
 })
 .argv;

console.log('hello ', argv.n);

用法如下。

$ hello morning -n tom
Good Morning
hello tom

可以将这个功能与 shellojs 模块结合起来。

#!/usr/bin/env node
require('shelljs/global');
var argv = require('yargs')
 .command("morning", "good morning", function (yargs) {
  echo("Good Morning");
 })
 .command("evening", "good evening", function (yargs) {
  echo("Good Evening");
 })
 .argv;

console.log('hello ', argv.n);

每个子命令往往有自己的参数,这时就需要在回调函数中单独指定。回调函数中,要先用 reset 方法重置 yargs 对象。

#!/usr/bin/env node
require('shelljs/global');
var argv = require('yargs')
 .command("morning", "good morning", function (yargs) { 
  echo("Good Morning");
  var argv = yargs.reset()
   .option("m", {
    alias: "message",
    description: "provide any sentence"
   })
   .help("h")
   .alias("h", "help")
   .argv;

  echo(argv.m);
 })
 .argv;

用法如下。

$ hello morning -m "Are you hungry?"
Good Morning
Are you hungry?

九、其他事项

(1)返回值

根据 Unix 传统,程序执行成功返回 0,否则返回 1 。

if (err) {
 process.exit(1);
} else {
 process.exit(0);
}

(2)重定向

Unix 允许程序之间使用管道重定向数据。

$ ps aux | grep 'node'

脚本可以通过监听标准输入的data 事件,获取重定向的数据。

process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(data) {
 process.stdout.write(data);
});

下面是用法。

$ echo 'foo' | ./hello
hello foo

(3)系统信号

操作系统可以向执行中的进程发送信号,process 对象能够监听信号事件。

process.on('SIGINT', function () {
 console.log('Got a SIGINT');
 process.exit(0);
});

发送信号的方法如下。

$ kill -s SIGINT [process_id]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery异步传输json数据格式实例代码
Nov 23 Javascript
js利用prototype调用Array的slice方法示例
Jun 09 Javascript
分享28款免费实用的 JQuery 图片和内容滑块插件
Dec 15 Javascript
js实现div拖动动画运行轨迹效果代码分享
Aug 27 Javascript
支持移动端原生js轮播图
Feb 16 Javascript
vue动态生成dom并且自动绑定事件
Apr 19 Javascript
vue上传图片组件编写代码
Jul 26 Javascript
JS判断用户用的哪个浏览器实例详解
Oct 09 Javascript
原生js通过一行代码实现简易轮播图
Jun 05 Javascript
electron 安装,调试,打包的具体使用
Nov 06 Javascript
JS动态显示倒计时效果
Dec 12 Javascript
JS图片懒加载的优点及实现原理
Jan 10 Javascript
详解vee-validate的使用个人小结
Jun 07 #Javascript
微信小程序多张图片上传功能
Jun 07 #Javascript
Vue.js对象转换实例
Jun 07 #Javascript
深入理解Angular4中的依赖注入
Jun 07 #Javascript
Vue中保存用户登录状态实例代码
Jun 07 #Javascript
jquery dataTable 后台加载数据并分页实例代码
Jun 07 #jQuery
jQuery用户头像裁剪插件cropbox.js使用详解
Jun 07 #jQuery
You might like
PHP内核探索:变量存储与类型使用说明
2014/01/30 PHP
Laravel ORM 数据model操作教程
2019/10/21 PHP
css如何让浮动元素水平居中
2015/08/07 Javascript
window.onload使用指南
2015/09/13 Javascript
Bootstrap每天必学之进度条
2015/11/30 Javascript
jQuery实现页面滚动时智能浮动定位
2017/01/08 Javascript
鼠标经过出现气泡框的简单实例
2017/03/17 Javascript
JavaScript之DOM插入更新删除_动力节点Java学院整理
2017/07/03 Javascript
jQuery选择器_动力节点Java学院整理
2017/07/05 jQuery
详解Node.js利用node-git-server快速搭建git服务器
2017/09/27 Javascript
详解Vue路由钩子及应用场景(小结)
2017/11/07 Javascript
webpack4的迁移的使用方法
2018/05/25 Javascript
JavaScript常见JSON操作实例分析
2018/08/08 Javascript
vuex直接赋值的三种方法总结
2018/09/16 Javascript
web页面和微信小程序页面实现瀑布流效果
2018/09/26 Javascript
微信小程序实现留言板功能
2018/11/02 Javascript
JS删除String里某个字符的方法
2021/01/06 Javascript
用Node写一条配置环境的指令
2019/11/14 Javascript
JS获取表格视图所选行号的ids过程解析
2020/02/21 Javascript
使用npm命令提示: 'npm' 不是内部或外部命令,也不是可运行的程序的处理方法
2020/05/14 Javascript
在Django中创建URLconf相关的通用视图的方法
2015/07/20 Python
python实现朴素贝叶斯分类器
2018/03/28 Python
python调用百度REST API实现语音识别
2018/08/30 Python
获取Pytorch中间某一层权重或者特征的例子
2019/08/17 Python
python爬虫模块URL管理器模块用法解析
2020/02/03 Python
Python写出新冠状病毒确诊人数地图的方法
2020/02/12 Python
Python抓包程序mitmproxy安装和使用过程图解
2020/03/02 Python
详解django使用include无法跳转的解决方法
2020/03/19 Python
css3学习系列之移动属性详解
2017/07/04 HTML / CSS
德国最大的婴儿用品网上商店:Kidsroom.de(支持中文)
2020/09/02 全球购物
出国考察邀请函
2014/01/21 职场文书
如何打造一封优秀的留学推荐信
2014/01/25 职场文书
2014县委书记四风对照检查材料思想汇报
2014/09/21 职场文书
《雪域豹影》读后感:父爱的伟大
2019/12/23 职场文书
Python基础之赋值,浅拷贝,深拷贝的区别
2021/04/30 Python
解决Navicat for Mysql连接报错1251的问题(连接失败)
2021/05/27 MySQL