详解Node.js 命令行程序开发教程
一种编程语言是否易用,很大程度上,取决于开发命令行程序的能力。
Node.js作为目前最热门的开发工具之一,怎样使用它开发命令行程序,是Web开发者应该掌握的技能。
下面就是我在它的基础上扩展的教程,应该是目前最好的解决方案了。
一、可执行脚本
我们从最简单的讲起。
首先,使用JavaScript语言,写一个可执行脚本hello。
#!/usr/bin/envnode console.log('helloworld');
然后,修改hello的权限。
$chmod755hello
现在,hello就可以执行了。
$./hello helloworld
如果想把hello前面的路径去除,可以将hello的路径加入环境变量PATH。但是,另一种更好的做法,是在当前目录下新建package.json,写入下面的内容。
{ "name":"hello", "bin":{ "hello":"hello" } }
然后执行npmlink命令。
$npmlink
现在再执行hello,就不用输入路径了。
$hello helloworld
二、命令行参数的原始写法
命令行参数可以用系统变量process.argv获取。
下面是一个脚本hello。
#!/usr/bin/envnode console.log('hello',process.argv[2]);
执行时,直接在脚本文件后面,加上参数即可。
$./hellotom hellotom
上面代码中,实际上执行的是node./hellotom,对应的process.argv是['node','/path/to/hello','tom']。
三、新建进程
脚本可以通过child_process模块新建子进程,从而执行Unix系统命令。
#!/usr/bin/envnode varname=process.argv[2]; varexec=require('child_process').exec; varchild=exec('echohello'+name,function(err,stdout,stderr){ if(err)throwerr; console.log(stdout); });
用法如下。
$./hellotom hellotom
四、shelljs模块
shelljs模块重新包装了child_process,调用系统命令更加方便。它需要安装后使用。
npminstall--saveshelljs
然后,改写脚本。
#!/usr/bin/envnode varname=process.argv[2]; varshell=require("shelljs"); shell.exec("echohello"+name);
上面代码是shelljs的本地模式,即通过exec方法执行shell命令。此外还有全局模式,允许直接在脚本中写shell命令。
require('shelljs/global'); if(!which('git')){ echo('Sorry,thisscriptrequiresgit'); 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('gitcommit-am"Auto-commit"').code!==0){ echo('Error:Gitcommitfailed'); exit(1); }
五、yargs模块
shelljs只解决了如何调用shell命令,而yargs模块能够解决如何处理命令行参数。它也需要安装。
$npminstall--saveyargs
yargs模块提供argv对象,用来读取命令行参数。请看改写后的hello。
#!/usr/bin/envnode varargv=require('yargs').argv; console.log('hello',argv.name);
使用时,下面两种用法都可以。
$hello--name=tom hellotom $hello--nametom hellotom
也就是说,process.argv的原始返回值如下。
$nodehello--name=tom ['node', '/path/to/myscript.js', '--name=tom']
yargs可以上面的结果改为一个对象,每个参数项就是一个键值对。
varargv=require('yargs').argv; //$nodehello--name=tom //argv={ //name:tom //};
如果将argv.name改成argv.n,就可以使用一个字母的短参数形式了。
$hello-ntom hellotom
可以使用alias方法,指定name是n的别名。
#!/usr/bin/envnode varargv=require('yargs') .alias('n','name') .argv; console.log('hello',argv.n);
这样一来,短参数和长参数就都可以使用了。
$hello-ntom hellotom $hello--nametom hellotom
argv对象有一个下划线(_)属性,可以获取非连词线开头的参数。
#!/usr/bin/envnode varargv=require('yargs').argv; console.log('hello',argv.n); console.log(argv._);
用法如下。
$helloA-ntomBC hellotom ['A','B','C']
六、命令行参数的配置
yargs模块还提供3个方法,用来配置命令行参数。
- demand:是否必选
- default:默认值
- describe:提示
#!/usr/bin/envnode varargv=require('yargs') .demand(['n']) .default({n:'tom'}) .describe({n:'yourname'}) .argv; console.log('hello',argv.n);
上面代码指定n参数不可省略,默认值为tom,并给出一行提示。
options方法允许将所有这些配置写进一个对象。
#!/usr/bin/envnode varargv=require('yargs') .option('n',{ alias:'name', demand:true, default:'tom', describe:'yourname', type:'string' }) .argv; console.log('hello',argv.n);
有时,某些参数不需要值,只起到一个开关作用,这时可以用boolean方法指定这些参数返回布尔值。
#!/usr/bin/envnode varargv=require('yargs') .boolean(['n']) .argv; console.log('hello',argv.n);
上面代码中,参数n总是返回一个布尔值,用法如下。
$hello hellofalse $hello-n hellotrue $hello-ntom hellotrue
boolean方法也可以作为属性,写入option对象。
#!/usr/bin/envnode varargv=require('yargs') .option('n',{ boolean:true }) .argv; console.log('hello',argv.n);
七、帮助信息
yargs模块提供以下方法,生成帮助信息。
- usage:用法格式
- example:提供例子
- help:显示帮助信息
- epilog:出现在帮助信息的结尾
#!/usr/bin/envnode varargv=require('yargs') .option('f',{ alias:'name', demand:true, default:'tom', describe:'yourname', type:'string' }) .usage('Usage:hello[options]') .example('hello-ntom','sayhellotoTom') .help('h') .alias('h','help') .epilog('copyright2015') .argv; console.log('hello',argv.n);
执行结果如下。
$hello-h Usage:hello[options] Options: -f,--nameyourname[string][required][default:"tom"] -h,--helpShowhelp[boolean] Examples: hello-ntomsayhellotoTom copyright2015
八、子命令
yargs模块还允许通过command方法,设置Git风格的子命令。
#!/usr/bin/envnode varargv=require('yargs') .command("morning","goodmorning",function(yargs){ console.log("GoodMorning"); }) .command("evening","goodevening",function(yargs){ console.log("GoodEvening"); }) .argv; console.log('hello',argv.n);
用法如下。
$hellomorning-ntom GoodMorning hellotom
可以将这个功能与shellojs模块结合起来。
#!/usr/bin/envnode require('shelljs/global'); varargv=require('yargs') .command("morning","goodmorning",function(yargs){ echo("GoodMorning"); }) .command("evening","goodevening",function(yargs){ echo("GoodEvening"); }) .argv; console.log('hello',argv.n);
每个子命令往往有自己的参数,这时就需要在回调函数中单独指定。回调函数中,要先用reset方法重置yargs对象。
#!/usr/bin/envnode require('shelljs/global'); varargv=require('yargs') .command("morning","goodmorning",function(yargs){ echo("GoodMorning"); varargv=yargs.reset() .option("m",{ alias:"message", description:"provideanysentence" }) .help("h") .alias("h","help") .argv; echo(argv.m); }) .argv;
用法如下。
$hellomorning-m"Areyouhungry?" GoodMorning Areyouhungry?
九、其他事项
(1)返回值
根据Unix传统,程序执行成功返回0,否则返回1。
if(err){ process.exit(1); }else{ process.exit(0); }
(2)重定向
Unix允许程序之间使用管道重定向数据。
$psaux|grep'node'
脚本可以通过监听标准输入的data事件,获取重定向的数据。
process.stdin.resume(); process.stdin.setEncoding('utf8'); process.stdin.on('data',function(data){ process.stdout.write(data); });
下面是用法。
$echo'foo'|./hello hellofoo
(3)系统信号
操作系统可以向执行中的进程发送信号,process对象能够监听信号事件。
process.on('SIGINT',function(){ console.log('GotaSIGINT'); process.exit(0); });
发送信号的方法如下。
$kill-sSIGINT[process_id]
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。