一门编程语言好不好用,很大程度上取决于命令行程序的开发能力。Node.js是目前最流行的开发工具之一,如何使用它来开发命令行程序是Web开发者应该掌握的技能。最近npm的博客有一系列的文章,我觉得写的很好。下面是我在上面展开的教程,应该是目前最好的解决方案了。1.可执行脚本让我们从最简单的开始。首先,使用JavaScript语言编写一个可执行脚本hello。#!/usr/bin/envnodeconsole.log('你好世界');然后,修改hello的权限。$chmod755hello现在可以执行hello了。$./hellohelloworld如果想去掉hello前面的路径,可以将hello的路径添加到环境变量PATH中。不过,另一种更好的方法是在当前目录下新建一个package.json,写入如下内容。{"name":"hello","bin":{"hello":"hello"}}然后执行npm链接命令。$npmlink现在执行hello,就不用输入路径了。$hellohelloworld2.命令行参数的原始写法命令行参数可以通过系统变量process.argv获取。#!/usr/bin/envnodeconsole.log('你好',process.argv[2]);执行时直接在脚本文件后面加上参数即可。$./hellotomhellotom3.新建进程脚本可以通过child_process模块??创建子进程来执行Unix系统命令。#!/usr/bin/envnodevarname=process.argv[2];varexec=require('child_process').exec;varchild=exec('echohello'+name,function(err,stdout,stderr)复制代码{if(err)抛出错误;console.log(stdout);});用法如下。$./hellotomhellotom4.shelljs模块shelljs模块对child_process进行了重新封装,调用系统命令更加方便。需要安装才能使用。npminstall--saveshelljs然后,重写脚本。#!/usr/bin/envnodevarname=process.argv[2];varshell=require("shelljs");shell.exec("echohello"+name);上面的代码是shelljs的本地模式,即通过exec方法执行一个shell命令。还有glob模式,它允许直接在脚本中编写shell命令。require('shelljs/global');if(!which('git')){echo('抱歉,这个脚本需要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('gitcommit-am"Auto-commit"').code!==0){echo('Error:Gitcommitfailed');exit(1);}5、yargs模块shelljs只解决如何调用shell命令,而yargs模块可以解决如何处理命令行参数。它还需要安装。$npminstall--saveyargsyargs模块提供了一个argv对象来读取命令行参数。看看重写的hello。#!/usr/bin/envnodevarargv=require('yargs').argv;console.log('你好',argv.name);使用时,有以下两种用法。$hello--name=tomhellotom$hello--nametomhellotom如果将argv.name改为argv.n,则可以使用一个字母的短参数形式。$hello-ntomhellotom可以使用alias方法指定name是n的别名。#!/usr/bin/envnodevarargv=require('yargs').alias('n','name').argv;console.log('你好',argv.n);这样就可以使用短参数和长参数。$hello-ntomhellotom$hello--nametomhellotomargv对象有一个下划线(_)属性,可以获取非连字符行开头的参数。#!/usr/bin/envnodevarargv=require('yargs').argv;console.log('你好',argv.n);控制台日志(argv._);用法如下。$helloA-ntomBChellotom['A','B','C']6.命令行参数的配置yargs模块也提供了3种配置命令行参数的方法。demand:是否需要default:默认值describe:prompt#!/usr/bin/envnodevarargv=require('yargs').demand(['n']).default({n:'tom'}).describe({n:'你的名字'}).argv;console.log('你好',argv.n);上面代码指定n参数不能省略,默认值为tom,并给出一行提示。options方法允许将所有这些配置写入一个对象。#!/usr/bin/envnodevarargv=require('yargs').option('n',{别名:'name',demand:true,default:'tom',describe:'yourname',type:'string'}).argv;console.log('hello',argv.n);有时候,有些参数不需要取值,只是起到一个开关的作用。这时候可以使用boolean方法指定这些参数返回布尔值。#!/usr/bin/envnodevarargv=require('yargs').boolean(['n']).argv;console.log('hello',argv.n);上面代码中,参数n总是返回一个布尔值,用法如下。$hellohellofalse$hello-nhellotrue$hello-ntomhellotrue布尔方法也可以作为一个属性写入选项对象。#!/usr/bin/envnodevarargv=require('yargs').option('n',{boolean:true}).argv;console.log('hello',argv.n);七。帮助信息yargs模块提供了以下方法来生成帮助信息。usage:使用格式示例:提供示例help:显示帮助信息epilog:出现在帮助信息末尾#!/usr/bin/envnodevarargv=require('yargs').option('f',{alias:'name',demand:true,default:'tom',describe:'yourname',type:'string'}).usage('Usage:hello[选项]').example('hello-ntom','向汤姆问好').help('h').alias('h','help').epilog('copyright2015').argv;console.log('hello',argv.n);执行结果如下。$hello-hUsage:hello[options]选项:-f,--nameyourname[string][required][default:"tom"]-h,--helpShowhelp[boolean]Examples:hello-ntomsayhellotoTomcopyright20158.子命令yargs模块还允许通过command方法设置Git风格的子命令。#!/usr/bin/envnodevarargv=require('yargs').command("morning","goodmorning",function(yargs){console.log("GoodMorning");}).command("晚上”,“晚上好”,功能(yargs){console.log(“晚上好”);}).argv;console.log('你好',argv.n);用法如下。$hellomorning-ntomGoodMorninghellotom可以将这个功能与shellojs模块结合起来。#!/usr/bin/envnoderequire('shelljs/global');varargv=require('yargs').command("morning","goodmorning",function(yargs){echo("早安");}).command("晚上好","晚上好",function(yargs){echo("晚上好");}).argv;console.log('你好',argv.n);每个子命令往往都有自己的参数,那么需要在回调函数中单独指定。在回调函数中,yargs对象必须先用reset方法重置。#!/usr/bin/envnoderequire('shelljs/global');varargv=require('yargs').command("morning","goodmorning",function(yargs){echo("早安");varargv=yargs.reset().option("m",{alias:"message",description:"provideanysentence"}).help("h").alias("h","help").argv;echo(argv.m);}).argv;用法如下。$hellomorning-m“你饿了吗?”早上好,你饿了吗?9.其他事项(1)返回值按照Unix传统,程序成功返回0,否则返回1。if(err){process.exit(1);}else{process.exit(0);}(2)重定向Unix允许使用管道在程序之间重定向数据。$辅助|grep‘node’脚本可以通过监听标准输入的数据事件来获取重定向的数据。process.stdin.resume();process.stdin.setEncoding('utf8');process.stdin.on('data',function(data){process.stdout.write(data);});这是用法:$echo'foo'|./hellohellofoo(3)系统信号操作系统可以向正在运行的进程发送信号,进程对象可以监听信号事件。process.on('SIGINT',function(){console.log('GotaSIGINT');process.exit(0);});发送信号的方法如下。$kill-sSIGINT[进程号]
