激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - Node.js 中如何收集和解析命令行參數

Node.js 中如何收集和解析命令行參數

2021-12-28 17:44descire node.js

這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

在開發 CLI(Command Line Interface)工具的業務場景下,離不開命令行參數的收集和解析。

接下來,本文介紹如何收集和解析命令行參數。

收集命令行參數

在 Node.js 中,可以通過 process.argv 屬性收集進程被啟動時傳入的命令行參數:

?
1
2
3
4
5
6
7
8
// ./example/demo.js
process.argv.slice(2);
 
// 命令行執行如下命令
node ./example/demo.js --name=xiaoming --age=20 man
 
// 得到的結果
[ '--name=xiaoming', '--age=20', 'man' ]

由上述示例可以發現,Node.js 在處理命令行參數時,只是簡單地通過空格來分割字符串。

對于這樣的參數數組,無法很方便地獲取到每個參數對應的值,所以需要再進行一次解析操作。

命令行參數風格

在解析命令行參數之前,需要了解一些常見的命令行參數風格:

  • Unix 風格:參數以「-」(連字符)開頭
  • GNU 風格:參數以「--」(雙連字符)開頭
  • BSD 風格:參數以空格分割

Unix 參數風格有一個特殊的注意事項:「「-」后面緊鄰的每一個字母都表示一個參數名」。

?
1
ls -al

上述命令用來顯示當前目錄下所有的文件、文件夾并且顯示它們的詳細信息,等同于:

?
1
ls -a -l

GNU 風格的參數以 「--」開頭,一般后面會跟上一個單詞或者短語,例如熟悉的 npm 安裝依賴的命令:

?
1
npm install --save koa

對于兩個單詞的情況,在 GNU 參數風格中,會通過「-」來連接,例如 npm 安裝僅用于開發環境的依賴:

?
1
npm install --save-dev webpack

BSD 是加州大學伯克利分校開發的一個 Unix 版本。其與 Unix 的區別主要在于參數前面沒有 「-」,個人感覺這樣很難區別參數和參數值。

注意事項:-- 后面緊鄰空格時,表示后面的字符串不需要解析。

解析命令行參數

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function parse(args = []) {
 // _ 屬性用來保留不需要處理的參數字符串
 const output = { _: [] };
 
 for (let index = 0; index < args.length; index++) {
  const arg = args[index];
  
  if (isIgnoreFollowingParameters(output, args, index, arg)) {
   break;
  }
  
  if (!isParameter(arg)) {
   output._.push(arg);
   continue;
  }
 
  ...
 }
 
 return output;
}
 
parse(process.argv.slice(2));

接收到命令行參數數組之后,需要遍歷數組,處理每一個參數字符串。

isIgnoreFollowingParameters 方法主要用來判斷單個「--」的場景,后續的參數字符串不再需要處理:

?
1
2
3
4
5
6
7
function isIgnoreFollowingParameters(output, args, index, arg) {
 if (arg !== '--') {
  return false;
 }
 output._ = output._.concat(args.slice(++index));
 return true;
}

接下來,如果參數字符串不以「-」開頭,同樣也不需要處理,參數的形式以 Unix 和 GNU 風格為主:

?
1
2
3
function isParameter(arg) {
 return arg.startsWith('-');
}

參數的表現形式主要分為以下幾種:

  • "--name=xiaoming": 參數名為 name,參數值為 xiaoming
  • "-abc=10": 參數名為 a,參數值為 true;參數名為 b,參數值為 true;參數名為 c,參數值為 10
  • "--save-dev": 參數名為 save-dev,參數值為 true
  • "--age 20":參數名為 age,參數值為 20
?
1
2
3
4
5
6
7
8
9
10
11
12
13
let hyphensIndex;
for (hyphensIndex = 0; hyphensIndex < arg.length; hyphensIndex++) {
 if (arg.charCodeAt(hyphensIndex) !== 45) {
  break;
 }
}
 
let assignmentIndex;
for (assignmentIndex = hyphensIndex + 1; assignmentIndex < arg.length; assignmentIndex++) {
 if (arg[assignmentIndex].charCodeAt(0) === 61) {
  break;
 }
}

利用 Unicode 碼點值找出連字符和等號的下標值,從而根據下標分割出參數名和參數值:

?
1
2
3
4
const name = arg.substring(hyphensIndex, assignmentIndex);
 
let value;
const assignmentValue = arg.substring(++assignmentIndex);

處理參數值時,需要考慮參數賦值的四種場景:

?
1
2
3
4
5
6
7
8
9
if (assignmentValue) {
 value = assignmentValue; // --name=xiaoming or -abc=10
} else if (index + 1 === args.length) {
 value = true; // --save-dev
} else if (('' + args[index + 1]).charCodeAt(0) !== 45) {
 value = args[++index]; // --age 20
} else {
 value = true; // 缺省情況
}

由于 Unix 風格中每一個字母都代表一個參數,并且「手動傳遞的參數值應該賦值給最后一個參數」,所以還需針對該場景進行適配:

?
1
2
3
4
5
6
7
// 「-」or「--」
const arr = hyphensIndex === 2 ? [name] : name;
for (let keyIndex = 0; keyIndex < arr.length; keyIndex++) {
 const _key = arr[keyIndex];
 const _value = keyIndex + 1 < arr.length || value;
 handleKeyValue(output, _key, _value);
}

最后針對參數的賦值操作,需要考慮到「多次賦值」的情況:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function handleKeyValue(output, key, value) {
 const oldValue = output[key];
 if (Array.isArray(oldValue)) {
  output[key] = oldValue.concat(value);
  return;
 }
 
 if (oldValue) {
  output[key] = [oldValue, value];
  return;
 }
 
 output[key] = value;
}

到此,命令行參數的解析功能就完成了,上述方法執行的效果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
# 命令行執行
node ./example/step1.js --name=xiaoming --age 20 --save-dev -abc=10 -c=20 -- --ignore
 
# 解析結果
{
 _: [ '--ignore' ],
 name: 'xiaoming',
 age: '20',
 'save-dev': true,
 a: true,
 b: true,
 c: [ '10', '20' ]
}

別名機制

比較優秀的 CLI 工具在參數的解析上都支持參數的別名設置,例如使用 npm 安裝開發環境依賴時,你可以選擇這種完整的寫法:

?
1
npm install --save-dev webpack

你也可以使用下面這種別名方式:

?
1
npm install -D webpack

 

從使用上來說 -D 和 --save-dev 是兩種方式,但是從 CLI 工具的開發者來說,最終處理邏輯時只能以一個參數名為標準,所以對于一個命令行參數解析庫來說,其結果需要包含所有的情況:

?
1
2
3
npm install --save-dev webpack
# 解析的結果
{ 'save-dev': true, 'D': true }

以上文的解析方法為例,需要添加額外的選項參數,加入 alias 屬性來聲明別名屬性的對應關系:

?
1
2
3
4
5
parse(process.argv.slice(2), {
 alias: {
  'save-dev': 'S'
 }
})

上述方式符合正常的理解:設置參數對應的別名。但這是一個「單向查找關系」,需要轉化為:

?
1
2
3
4
"alias": {
 "save-dev": ["s"],
 "s": ["save-dev"]
}

因為對于使用者來說,只會選擇一種方式傳遞參數。對于開發者的話需要根據任意一個別名找到其相關聯的別名:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function parse(args = [], options = {}) {
 const output = { _: [] };
 
 const { alias } = options;
 
 const hasAlias = alias !== void 666;
 
 if (hasAlias) {
  Object.keys(alias).forEach(key => {
   alias[key] = toArr(alias[key]);
   alias[key].forEach((item, index) => {
    (alias[item] = alias[key].concat(key)).splice(index, 1);
   })
  })
 }
 
 // 省略解析代碼
 ...
 
 if (hasAlias) {
  Object.keys(output).forEach(key => {
   const arr = alias[key] || [];
   arr.forEach(sub => output[sub] = output[key])
  })
 }
 
 return output;
}

除了別名之外,還可以在參數解析之后做如下優化:

  • 參數值的類型約束
  • 參數的默認值設定

成熟的解析庫

針對一些成熟的命令行參數解析庫可以采用基準測試查看它們的解析效率:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const nopt = require('nopt');
const mri = require('mri');
const yargs = require('yargs-parser');
const minimist = require('minimist');
const { Suite } = require('benchmark');
 
const bench = new Suite();
const args = ['--name=xiaoming', '-abc', '10', '--save-dev', '--age', '20'];
 
bench
 .add('minimist   ', () => minimist(args))
 .add('mri     ', () => mri(args))
 .add('nopt     ', () => nopt(args))
 .add('yargs-parser ', () => yargs(args))
 .on('cycle', e => console.log(String(e.target)))
 .run();

Node.js 中如何收集和解析命令行參數

本文的內容主要參考解析效率最高的 mri 庫的源碼,感興趣的同學可以學習其源碼實現。(順便吐槽一下:嵌套三元操作符可讀性真的很差。。)

雖然上述基準測試中 minimist 效率并不很好,但是其覆蓋了比較全的參數輸入場景。(以上測試用例覆蓋的場景有限)

到此這篇關于Node.js 中如何收集和解析命令行參數的文章就介紹到這了,更多相關Node.js 解析命令行參數內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/6915200398512881672

延伸 · 閱讀

精彩推薦
  • node.jslinux服務器快速卸載安裝node環境(簡單上手)

    linux服務器快速卸載安裝node環境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
  • node.js詳解node.js創建一個web服務器(Server)的詳細步驟

    詳解node.js創建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.jsnodejs中使用worker_threads來創建新的線程的方法

    nodejs中使用worker_threads來創建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.jsk8s node節點重新加入master集群的實現

    k8s node節點重新加入master集群的實現

    這篇文章主要介紹了k8s node節點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
主站蜘蛛池模板: 免费午夜视频在线观看 | 操操操操操| 国产羞羞视频免费在线观看 | 亚洲性综合网 | 一级免费大片 | 性欧美一区二区 | 国产成人午夜精品 | 午夜影院a | 色婷婷a | 国产精品久久久久久久久久三级 | 神马顶级推理片免费看 | 自拍偷拍亚洲图片 | av大全在线免费观看 | 欧美日韩免费一区 | 免费播放欧美毛片 | 日韩一级片免费 | 最新影院 | 欧美国产免费 | 在线成人免费观看 | 国产免费观看a大片的网站 欧美成人一级 | 免费一级毛片在线播放不收费 | 免费视频www在线观看 | 成人在线免费观看小视频 | 特级毛片a级毛片100免费 | 精品一区二区三区欧美 | 综合网天天色 | 高清国产午夜精品久久久久久 | 手机av免费在线 | 96视频在线免费观看 | 一及毛片视频 | 久久免费视频一区 | 欧美一级特黄aaaaaa在线看首页 | av播播 | 亚洲精品在线观看网站 | 欧美日韩国产成人在线观看 | 欧美精品在线视频观看 | 九九热精品视频在线 | 精品一区二区久久久久 | 一级黄色免费 | 国产一级在线看 | 国产色视频在线观看免费 |