Node.js 命令行程序開發教程

1. 可執行腳本

// 使用javascript語言編寫一個可執行腳本javascript

#! /usr/bin/env node
console.log('hello')
!/usr/bin/node 和 #! /usr/bin/env node 意思及區別

是Unix和Linux腳本語言的第一行,目的就是指出,你想要你的這個文件中的代碼用什麼可執行程序去運行它html

!/usr/bin/node是告訴操做系統執行這個腳本的時候,調用/usr/bin下的node解釋器;
!/usr/bin/env node這種用法是爲了防止操做系統用戶沒有將node裝在默認的/usr/bin路徑裏。當系統看到這一行的時候,首先會到env設置裏查找node的安裝路徑,再調用對應路徑下的解釋器程序完成操做。java

!/usr/bin/node至關於寫死了node路徑;
!/usr/bin/env node會去環境設置尋找node目錄,推薦這種寫法node

在命令行中輸入 hello
報錯 zsh: command not found: hello
修改權限 chmod 755 helloshell

chmod 755

/*
chmod是Linux下設置文件權限的命令,後面的數字表示不一樣用戶或用戶組的權限。npm

通常是三個數字:json

第一個數字表示文件全部者的權限數組

第二個數字表示與文件全部者同屬一個用戶組的其餘用戶的權限緩存

第三個數字表示其它用戶組的權限。安全

權限分爲三種:讀(r=4),寫(w=2),執行(x=1)。綜合起來還有可讀可執行(rx=5=4+1)、可讀可寫(rw=6=4+2)、可讀可寫可執行(rwx=7=4+2+1)。

因此,chmod 755 設置用戶的權限爲:

1.文件全部者可讀可寫可執行

2.與文件全部者同屬一個用戶組的其餘用戶可讀可執行

3.其它用戶組可讀可執行
*/

在命令行中輸入 ./hello
控制檯打印出hello

若是想直接執行 hello 去掉前面的./ 則有兩種方案

  1. 把當前hello文件的路徑放入到環境變量中
  2. 更好的作法是在當前目錄下建立一個package.json
{
    name: 'hello',
    "bin": {
        "hello": "hello"
    }
}

而後 npm link
再執行hello 就不用輸入路徑了

### 2.命令行參數的原始寫法

命令行參數能夠用系統的process.argv獲取

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

// [ '/usr/local/bin/node', '/usr/local/bin/hello', 'liu' ]
// process.argv 這個是一個數組,第一個參數是當前可執行程序的本機路徑  第二個參數是當前文本的路徑  第三個參數及之後的參數都是命令行參數

在命令行中輸入 hello liu 輸出 hello liu

3. 新建進程

腳本能夠經過child_process模塊新建子進程,從而執行Linux 命令

#!/usr/bin/env node
let name = process.argv[2];
let {exec} = require('child_process');
let child  = exec('echo hello '+name,(err,stdout,stderr)=>{
    if(err) throw err;
    console.info(stdout);
});
// child_process模塊用於新建子進程。子進程的運行結果儲存在系統緩存之中(最大200KB),等到子進程運行結束之後,主進程再用回調函數讀取子進程的運行結果。
// exec方法最多能夠接受兩個參數,第一個參數是所要執行的shell命令,第二個參數是回調函數,該函數接受三個參數,分別是發生的錯誤、標準輸出的顯示結果、標準錯誤的顯示結果。
// 因爲標準輸出和辨準錯誤都是流對象,能夠監聽data事件,所以上面的代碼能夠寫成下面的樣子

let child = exec('echo hello ' + name);
child.stdout.on('data', function(data){
    console.log('stdout:'+data)
})
child.stderr.on('data', function(data){
    console.log('stderr:'+data)
})

child.on('close', function(code){
    console.log('closing code:'+code)
})

// 上面的代碼還代表,子進程自己有close事件,能夠設置回調函數。

// 上面的代碼還有一個好處。監聽data事件之後,能夠實時輸出結果,不然只有等到子進程結束,纔會輸出結果。因此,若是子進程運行時間較長,或者是持續運行,第二種寫法更好。

exec()方法存在的問題?
exec方法會直接調用bash(bin/sh程序)即shell腳原本解析命令,因此若是有用戶輸入的參數,exec方法是不安全的

let exec = require('child_process').exec;
// exec('node -v', function (error, stdout, stderr) {
//     if (error !== null) {
//         console.log('exec error' + error)
//     }
//     console.log('stdout:' + stdout); // stdout:v8.9.3
//     console.log('stderr:' + stderr); // stderr:
// })

// node child.js

let path = ";user input";
exec('ls -l' + path, function (err, stdout, stderr) {
    console.log('輸出',stdout)
})

// 上面代碼表示,在bash環境下,ls -l; user input會直接運行。若是用戶輸入惡意代碼,將會帶來安全風險。所以,在有用戶輸入的狀況下,最好不使用exec方法,而是使用execFile方法。

execSync()
execSync是exec的同步執行版本。

它能夠接受兩個參數,第一個參數是所要執行的命令,第二個參數用來配置執行環境。

execFile()
execFile方法直接執行特定的程序,參數做爲數組傳入,不會被bash解釋,所以具備較高的安全性。

var child_process = require('child_process');

var path = ".";
child_process.execFile('/bin/ls', ['-l', path], function (err, result) {
    console.log(result)
});

上面代碼中,假定path來自用戶輸入,若是其中包含了分號或反引號,ls程序不理解它們的含義,所以也就得不到運行結果,安全性就獲得了提升。

4. yarys 模塊用於處理命令行參數

4.1 安裝

npm install yargs --save

4.2 讀取命令行參數

yargs模塊提供了argv對象來讀取命令行參數

#! /usr/bin/env node
let argv = require('yargs').argv
console.log('yargs'+ argv['_'][0] + argv['_'][1])
console.log(argv)

// ./yargs liu shiyu
// { _: [ 'liu', 'shiyu' ],
     help: false,
     version: false,
     '$0': 'yargs' 
  }
  // 從這個例子咱們發現 命令行所傳的參數 所有放在argv['_'] 的數組中
  console.log('yargs'+ argv.name)
  // yargs --name=liu
  // yargsliu

4.3 能夠指定別名

let argv require('yargs').alias('n','name').argv
// yargs --n liu
// yargsliu
{ _: [],
  help: false,
  version: false,
  n: 'liu',
  name: 'liu',
  '$0': 'yargs' 
}

4.4 下劃線屬性
argv對象有一個下劃線屬性,是一個數組,裏面存放的是非連詞線開頭的參數

#! /usr/bin/env node
let argv = require('yargs').argv
console.log('yargs'+ argv._)
// yargs liu shiyu
// [ 'liu', 'shiyu' ]

4.5 命令行參數的配置

demand 是否必選
default 默認值
describe 提示

```
#!/usr/bin/env node
let argv = require('yargs')
  .demand(['n'])
  .default({n:'liu'})
  .describe({n:"你的名字"})
  .argv;
 console.log('hello ',argv.n);
 // yargs
 // hello liu
 不傳的話取默認值
```

options 方法容許將全部的配置寫入配置對象

```
let yargs = require('yargs');
let argv = yargs.option('n',{
    alias: 'name',
    demand: true,
    describe: '請輸入你的名字',
    type: 'string',
}).argv

console.log('hello ' + argv.n)
// yargs --n=liushiyu
// yargs --name=liushiyu
// hello liushiyu
```

有時候,某些參數不須要,只起到開關的做用,能夠用boolean指定這些參數返回布爾值
#!/usr/bin/env node
let argv = require('yargs')
    .boolean(['private'])
    .argv
console.log('hello',argv.n);

4.6 幫助信息

yargs模塊提供如下方法,生成幫助信息

usage 用法格式
example 提供例子
help 顯示幫助信息
epilog 出如今幫助信息的結尾

let yargs = require('yargs');
let argv = yargs.option('n',{
    alias: 'name',
    demand: true,
    describe: '請輸入你的名字',
    type: 'string',
}).usage('Usage: yargs [options]')
    .example('yargs -n liu','say hello to liu')
    .help('h')
    .alias('h','help')
    .epilog('copyright 2018')
    .argv

console.log('hello ' + argv.n)

// 
Usage: yargs [options]

Options:
  --version   Show version number                                      [boolean]
  -n, --name  請輸入你的名字                                 [string] [required]
  -h, --help  Show help                                                [boolean]

Examples:
  yargs -n liu  say hello to liu

copyright 2018

Node.js 命令行程序開發教程

相關文章
相關標籤/搜索