如何将命令行参数传递给Node.js程序?

我有一个用Node.js编写的Web服务器,我想使用一个特定的文件夹启动。我不知道如何访问JavaScript中的参数。我正在运行这样的节点:

$ node server.js folder

这里server.js是我的服务器代码。Node.js帮助说明这是可能的:

$ node -hUsage: node [options] script.js [arguments]

我如何在JavaScript中访问这些参数?不知何故,我无法在网络上找到此信息。

1572089 次浏览

标准方法(无库)

参数存储在process.argv

这里是处理命令行参数的节点文档:

process.argv是一个包含命令行参数的数组。第一个元素将是“节点”,第二个元素将是JavaScript文件的名称。接下来的元素将是任何额外的命令行参数。

// print process.argvprocess.argv.forEach(function (val, index, array) {console.log(index + ': ' + val);});

这将产生:

$ node process-2.js one two=three four0: node1: /Users/mjr/work/node/process-2.js2: one3: two=three4: four

为了像常规javascript函数那样规范化参数,我在我的node.jsshell脚本中这样做:

var args = process.argv.slice(2);

请注意,第一个参数通常是nodejs的路径,第二个参数是您正在执行的脚本的位置。

节点优化

看看乐观库,它比手动解析命令行选项要好得多。

更新

乐观主义者已被弃用。尝试纱线,这是乐观主义者的积极分支。

Commander.js

非常适合定义您的选项、操作和参数。它还为您生成帮助页面。

立即

如果您喜欢回调方法,则非常适合从用户那里获取输入。

共同提示

如果您喜欢生成器方法,则非常适合从用户那里获取输入。

如果您的脚本名为myScript.js并且您想将名字和姓氏“Sean Worthington”作为参数传递,如下所示:

node myScript.js Sean Worthington

然后在你的脚本中你写:

var firstName = process.argv[2]; // Will be set to 'Sean'var lastName = process.argv[3]; // Will be set to 'Worthington'

stdio库

在NodeJS中解析命令行参数的最简单方法是使用标准输入输出模块。受UNIXgetopt实用程序的启发,它非常简单,如下所示:

var stdio = require('stdio');var ops = stdio.getopt({'check': {key: 'c', args: 2, description: 'What this option means'},'map': {key: 'm', description: 'Another description'},'kaka': {args: 1, required: true},'ooo': {key: 'o'}});

如果您使用此命令运行前面的代码:

node <your_script.js> -c 23 45 --map -k 23 file1 file2

然后ops对象将如下所示:

{ check: [ '23', '45' ],args: [ 'file1', 'file2' ],map: true,kaka: '23' }

所以你可以随心所欲地使用它。例如:

if (ops.kaka && ops.check) {console.log(ops.kaka + ops.check[0]);}

还支持分组选项,因此您可以编写-om而不是-o -m

此外,stdio可以自动生成帮助/使用输出。如果您调用ops.printHelp(),您将获得以下内容:

USAGE: node something.js [--check <ARG1> <ARG2>] [--kaka] [--ooo] [--map]-c, --check <ARG1> <ARG2>   What this option means (mandatory)-k, --kaka                  (mandatory)--map                       Another description-o, --ooo

如果没有给出强制选项(前面有错误消息)或错误指定(例如,如果您为选项指定了单个参数并且它需要2),也会显示上一条消息。

您可以使用NPM安装标准输入输出模块:

npm install stdio

您可以解析所有参数并检查它们是否存在。

档案:parse-cli-arguments.js:

module.exports = function(requiredArguments){var arguments = {};
for (var index = 0; index < process.argv.length; index++) {var re = new RegExp('--([A-Za-z0-9_]+)=([A/-Za-z0-9_]+)'),matches = re.exec(process.argv[index]);
if(matches !== null) {arguments[matches[1]] = matches[2];}}
for (var index = 0; index < requiredArguments.length; index++) {if (arguments[requiredArguments[index]] === undefined) {throw(requiredArguments[index] + ' not defined. Please add the argument with --' + requiredArguments[index]);}}
return arguments;}

而不仅仅是:

var arguments = require('./parse-cli-arguments')(['foo', 'bar', 'xpto']);

这里有几个很好的答案,但这一切似乎都非常复杂。这与bash脚本访问参数值的方式非常相似,并且正如MooGoo指出的那样,它已经提供了标准node.js。(只是为了让node.js的人理解)

示例:

$ node yourscript.js banana monkey
var program_name = process.argv[0]; //value will be "node"var script_path = process.argv[1]; //value will be "yourscript.js"var first_value = process.argv[2]; //value will be "banana"var second_value = process.argv[3]; //value will be "monkey"

最新的答案是使用极简主义库。我们曾经使用节点优化器,但它已经被弃用了。

以下是一个如何使用它的示例,直接取自极简留档:

var argv = require('minimist')(process.argv.slice(2));console.dir(argv);

-

$ node example/parse.js -a beep -b boop{ _: [], a: 'beep', b: 'boop' }

-

$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz{ _: [ 'foo', 'bar', 'baz' ],x: 3,y: 4,n: 5,a: true,b: true,c: true,beep: 'boop' }

有一个应用程序。嗯,模块。嗯,不止一个,可能数百个。

Yargs是其中一个有趣的,它的文档读起来很酷。

这是一个来自github/npm页面的示例:

#!/usr/bin/env nodevar argv = require('yargs').argv;console.log('(%d,%d)', argv.x, argv.y);console.log(argv._);

输出在这里(它读取带破折号等的选项,短和长,数字等)。

$ ./nonopt.js -x 6.82 -y 3.35 rum(6.82,3.35)[ 'rum' ]$ ./nonopt.js "me hearties" -x 0.54 yo -y 1.12 ho(0.54,1.12)[ 'me hearties', 'yo', 'ho' ]

命令行参数值得一看!

您可以使用主符号标准(了解更多)设置选项。这些命令都是等效的,设置相同的值:

$ example --verbose --timeout=1000 --src one.js --src two.js$ example --verbose --timeout 1000 --src one.js two.js$ example -vt 1000 --src one.js two.js$ example -vt 1000 one.js two.js

要访问这些值,首先创建一个选项定义列表,描述您的应用程序接受的选项。#0属性是一个setter函数(提供的值通过它传递),让您完全控制接收到的值。

const optionDefinitions = [{ name: 'verbose', alias: 'v', type: Boolean },{ name: 'src', type: String, multiple: true, defaultOption: true },{ name: 'timeout', alias: 't', type: Number }]

接下来,使用//命令行参数解析选项:

const commandLineArgs = require('command-line-args')const options = commandLineArgs(optionDefinitions)

options现在看起来像这样:

{src: ['one.js','two.js'],verbose: true,timeout: 1000}

高级用法

除了上述典型用法之外,您还可以配置命令行参数以接受更高级的语法形式。

基于命令的语法(git样式)在表单中:

$ executable <command> [options]

举个例子。

$ git commit --squash -m "This is my commit message"

命令和子命令语法(docker样式)形式:

$ executable <command> [options] <sub-command> [options]

举个例子。

$ docker run --detached --image centos bash -c yum install -y httpd

使用指南生成

可以使用命令行使用情况生成使用指南(通常在设置--help时打印)。有关如何创建它们的说明,请参阅下面的示例和阅读留档

一个典型的使用指南示例。

用法

聚合物cli使用指南是一个很好的现实例子。

用法

进一步阅读

还有很多要学习,请参阅的wiki的例子和留档。

传递、解析参数是一个简单的过程。Node为您提供process.argv属性,它是一个字符串数组,这是调用Node时使用的参数。数组的第一个条目是Node可执行文件,第二个条目是脚本的名称。

如果您使用以下属性运行脚本

$ node args.js arg1 arg2

文件:args.js

console.log(process.argv)

你会得到像这样的数组

 ['node','args.js','arg1','arg2']

2018年答案基于当前的野外趋势:


香草JavaScript参数解析:

const args = process.argv;console.log(args);

这将返回:

$ node server.js one two=three four['node', '/home/server.js', 'one', 'two=three', 'four']

官方文档


参数解析最常用的NPM包:

最小化:用于最小参数解析。

Commander.js:参数解析采用最多的模块。

:更轻的替代Commander.js

雅格:更复杂的参数解析(繁重)。

Vorpal.js:具有参数解析的成熟/交互式命令行应用程序。

npm install ps-grab

如果你想运行这样的东西:

node greeting.js --user Abdennour --website http://abdennoor.com

--

var grab=require('ps-grab');grab('--username') // return 'Abdennour'grab('--action') // return 'http://abdennoor.com'

或者类似:

node vbox.js -OS redhat -VM template-12332 ;

--

var grab=require('ps-grab');grab('-OS') // return 'redhat'grab('-VM') // return 'template-12332'

您可以使用system.args到达命令行参数。我使用下面的解决方案将参数解析为对象,因此我可以通过名称获取我想要的参数。

var system = require('system');
var args = {};system.args.map(function(x){return x.split("=")}).map(function(y){args[y[0]]=y[1]});

现在你不需要知道参数的索引。像args.whatever一样使用它

注意:您应该使用像file.js x=1 y=2这样的命名参数来使用这个解决方案。

一个简单的代码片段(如果需要的话):

var fs = require('fs'), objMod = {};
process.argv.slice(2).map(function(y, i) {y = y.split('=');if (y[0] && y[1]) objMod[y[0]] = y[1];else console.log('Error in argument number ' + (i+1));});

没有图书馆

如果您想在vanilla JS/ES6中执行此操作,您可以使用以下解决方案

只在nodejs>6工作

const args = process.argv.slice(2).map((val, i)=>{let object = {};let [regexForProp, regexForVal] = (() => [new RegExp('^(.+?)='), new RegExp('\=(.*)')] )();let [prop, value] = (() => [regexForProp.exec(val), regexForVal.exec(val)] )();if(!prop){object[val] = true;return object;} else {object[prop[1]] = value[1] ;return object}}).reduce((obj, item) => {let prop = Object.keys(item)[0];obj[prop] = item[prop];return obj;}, {});

而这个命令

node index.js host=http://google.com port=8080 production

将产生以下结果

console.log(args);//{ host:'http://google.com',port:'8080',production:true }console.log(args.host);//http://google.comconsole.log(args.port);//8080console.log(args.production);//true

p>p. s.请更正map中的代码并减少功能如果你找到更优雅的解决方案,谢谢;)

为什么没有库:使用Array.prototype.reduce()

const args = process.argv.slice(2).reduce((acc, arg) => {
let [k, v = true] = arg.split('=')acc[k] = vreturn acc
}, {})

对于这个命令node index.js count=2 print debug=false msg=hi

console.log(args) // { count: '2', print: true, debug: 'false', msg: 'hi' }

还有,

我们可以改变

    let [k, v = true] = arg.split('=')acc[k] = v

通过(更长)

    let [k, v] = arg.split('=')acc[k] = v === undefined ? true : /true|false/.test(v) ? v === 'true' : /[\d|\.]+/.test(v) ? Number(v) : v

自动解析布尔值和数字

console.log(args) // { count: 2, print: true, debug: false, msg: 'hi' }

如节点文档中所述process.argv属性返回一个数组,其中包含启动Node.js进程时传递的命令行参数。

例如,假设以下脚本用于process-args.js:

// print process.argvprocess.argv.forEach((val, index) => {console.log(`${index}: ${val}`);});

启动Node.js过程为:

 $ node process-args.js one two=three four

将生成输出:

0: /usr/local/bin/node1: /Users/mjr/work/node/process-args.js2: one3: two=three4: four

大多数人都给出了很好的答案。我也想在这里贡献一些东西。我使用lodash库来迭代我们在启动应用程序时传递的所有命令行参数来提供答案:

// Lodash libraryconst _ = require('lodash');
// Function that goes through each CommandLine Arguments and prints it to the console.const runApp = () => {_.map(process.argv, (arg) => {console.log(arg);});};
// Calling the function.runApp();

要运行上述代码,只需运行以下命令:

npm installnode index.js xyz abc 123 456

结果将是:

xyzabc123456

在Node.js中检索参数的最简单方法是通过process.argv数组。这是一个全局对象,您无需导入任何其他库即可使用它。您只需将参数传递给Node.js应用程序,就像我们之前展示的那样,这些参数可以通过process.argv数组在应用程序中访问。

process.argv数组的第一个元素始终是指向节点可执行文件的文件系统路径。第二个元素是正在执行的JavaScript文件的名称。第三个元素是用户实际传递的第一个参数。

'use strict';
for (let j = 0; j < process.argv.length; j++) {console.log(j + ' -> ' + (process.argv[j]));}

这个脚本所做的只是循环遍历process.argv数组并打印索引以及存储在这些索引中的元素。

您还可以使用像vargs这样的库来处理逗号行参数。

process.argv是你的朋友,Node JS本身就支持捕获命令行参数。参见下面的示例::

process.argv.forEach((val, index) => {console.log(`${index}: ${val}`);})

proj.js

for(var i=0;i<process.argv.length;i++){console.log(process.argv[i]);}

终端:

nodemon app.js "arg1" "arg2" "arg3"

结果:

0 'C:\\Program Files\\nodejs\\node.exe'1 'C:\\Users\\Nouman\\Desktop\\Node\\camer nodejs\\proj.js'2 'arg1' your first argument you passed.3 'arg2' your second argument you passed.4 'arg3' your third argument you passed.

解释:

  1. 机器中node.exe的目录(C:\Program Files\nodejs\node.exe
  2. 项目文件的目录(proj.js
  3. 节点的第一个参数(arg1
  4. 节点的第二个参数(arg2
  5. 节点的第三个参数(arg3

您的实际参数从argv数组的第二索引开始,即process.argv[2]

这是我对命名参数的0-dep解决方案:

const args = process.argv.slice(2).map(arg => arg.split('=')).reduce((args, [value, key]) => {args[value] = key;return args;}, {});
console.log(args.foo)console.log(args.fizz)

示例:

$ node test.js foo=bar fizz=buzzbarbuzz

注意:当参数包含=时,自然会失败。这只适用于非常简单的用法。

虽然上面的答案是完美的,而且有人已经提出了纱线,但使用这个包真的很容易。这是一个很好的包,使得将参数传递到命令行非常容易。

npm i yargsconst yargs = require("yargs");const argv = yargs.argv;console.log(argv);

请访问https://yargs.js.org/了解更多信息。

没有将标志格式化为简单对象的libs

function getArgs () {const args = {};process.argv.slice(2, process.argv.length).forEach( arg => {// long argif (arg.slice(0,2) === '--') {const longArg = arg.split('=');const longArgFlag = longArg[0].slice(2,longArg[0].length);const longArgValue = longArg.length > 1 ? longArg[1] : true;args[longArgFlag] = longArgValue;}// flagselse if (arg[0] === '-') {const flags = arg.slice(1,arg.length).split('');flags.forEach(flag => {args[flag] = true;});}});return args;}const args = getArgs();console.log(args);

示例

简单

输入

node test.js -D --name=Hello

输出

{ D: true, name: 'Hello' }

真实世界

输入

node config/build.js -lHRs --ip=$HOST --port=$PORT --env=dev

输出

{l: true,H: true,R: true,s: true,ip: '127.0.0.1',port: '8080',env: 'dev'}

传递参数很容易,接收它们只是读取Node可以从任何地方访问的process.argv数组的问题。但是你肯定想把它们作为键/值对读取,所以你需要一个脚本来解释它。

Joseph Merdrignac用duce发布了一个漂亮的版本,但它依赖于key=value语法,而不是-k value--key value。为了使用第二个标准,我重写了它,它更丑,更长。我会把它作为一个答案发布,因为它不适合作为评论。但它确实完成了工作。

   const args = process.argv.slice(2).reduce((acc,arg,cur,arr)=>{if(arg.match(/^--/)){acc[arg.substring(2)] = trueacc['_lastkey'] = arg.substring(2)} elseif(arg.match(/^-[^-]/)){for(key of arg.substring(1).split('')){acc[key] = trueacc['_lastkey'] = key}} elseif(acc['_lastkey']){acc[acc['_lastkey']] = argdelete acc['_lastkey']} elseacc[arg] = trueif(cur==arr.length-1)delete acc['_lastkey']return acc},{})

使用此代码,命令node script.js alpha beta -charlie delta --echo foxtrot将为您提供以下对象

args = {"alpha":true,"beta":true,"c":true,"h":true,"a":true,"r":true"l":true,"i":true,"e":"delta","echo":"foxtrot"}

ES6风格的无依赖解决方案:

const longArgs = arg => {const [ key, value ] = arg.split('=');return { [key.slice(2)]: value || true }};
const flags = arg => [...arg.slice(1)].reduce((flagObj, f) => ({ ...flagObj, [f]: true }), {});

const args = () =>process.argv.slice(2).reduce((args, arg) => ({...args,...((arg.startsWith('--') && longArgs(arg)) || (arg[0] === '-' && flags(arg)))}), {});
console.log(args());

基于标准输入解析参数(--key=value

const argv = (() => {const arguments = {};process.argv.slice(2).map( (element) => {const matches = element.match( '--([a-zA-Z0-9]+)=(.*)');if ( matches ){arguments[matches[1]] = matches[2].replace(/^['"]/, '').replace(/['"]$/, '');}});return arguments;})();

命令示例

node app.js --name=stackoverflow --id=10 another-argument --text="Hello World"

Argv的结果:console.log(argv)

{name: "stackoverflow",id: "10",text: "Hello World"}

没有库的TypeScript解决方案:

interface IParams {[key: string]: string}
function parseCliParams(): IParams {const args: IParams = {};const rawArgs = process.argv.slice(2, process.argv.length);rawArgs.forEach((arg: string, index) => {// Long arguments with '--' flags:if (arg.slice(0, 2).includes('--')) {const longArgKey = arg.slice(2, arg.length);const longArgValue = rawArgs[index + 1]; // Next value, e.g.: --connection connection_nameargs[longArgKey] = longArgValue;}// Shot arguments with '-' flags:else if (arg.slice(0, 1).includes('-')) {const longArgKey = arg.slice(1, arg.length);const longArgValue = rawArgs[index + 1]; // Next value, e.g.: -c connection_nameargs[longArgKey] = longArgValue;}});return args;}
const params = parseCliParams();console.log('params: ', params);

输入:ts-node index.js -p param --parameter parameter

输出:{ p: 'param ', parameter: 'parameter' }

我扩展了getArgs函数只是为了获取命令,以及标志(-f--anotherflag)和命名args(--data=blablabla):

  1. 该模块
/*** @module getArgs.js* get command line arguments (commands, named arguments, flags)** @see https://stackoverflow.com/a/54098693/1786393** @return {Object}**/function getArgs () {const commands = []const args = {}process.argv.slice(2, process.argv.length).forEach( arg => {// long argif (arg.slice(0,2) === '--') {const longArg = arg.split('=')const longArgFlag = longArg[0].slice(2,longArg[0].length)const longArgValue = longArg.length > 1 ? longArg[1] : trueargs[longArgFlag] = longArgValue}// flagselse if (arg[0] === '-') {const flags = arg.slice(1,arg.length).split('')flags.forEach(flag => {args[flag] = true})}else {// commandscommands.push(arg)}})return { args, commands }}

// testif (require.main === module) {// node getArgs test --dir=examples/getUserName --start=getUserName.askNameconsole.log( getArgs() )}
module.exports = { getArgs }
  1. 使用示例:
$ node lib/getArgs test --dir=examples/getUserName --start=getUserName.askName{args: { dir: 'examples/getUserName', start: 'getUserName.askName' },commands: [ 'test' ]}
$ node lib/getArgs --dir=examples/getUserName --start=getUserName.askName test tutorial{args: { dir: 'examples/getUserName', start: 'getUserName.askName' },commands: [ 'test', 'tutorial' ]}

您可以从process.argv()获取命令行信息

我不想把问题限制在node.js。相反,我想把它变成如何解析字符串作为参数。

console.log(ArgumentParser(`--debug --msg="Hello World" --title="Test" --desc=demo -open --level=5 --MyFloat=3.14`))

输出

{"debug": true,"msg": "Hello World","title": "Test","desc": "demo","open": true,"level": 5,"MyFloat": 3.14}

代码

纯javascript,无需依赖

// 👇 Below is Test(() => {window.onload = () => {const testArray = [`--debug --msg="Hello World" --title="Test" --desc=demo -open --level=5 --MyFloat=3.14`,]for (const testData of testArray) {try {const obj = ArgumentParser(testData)console.log(obj)} catch (e) {console.error(e.message)}}}})()
// 👇 Scriptclass ParserError extends Error {
}
function Cursor(str, pos) {this.str = strthis.pos = posthis.MoveRight = (step = 1) => {this.pos += step}
this.MoveToNextPara = () => {const curStr = this.str.substring(this.pos)const match = /^(?<all> *--?(?<name>[a-zA-Z_][a-zA-Z0-9_]*)(=(?<value>[^-]*))?)/g.exec(curStr) // https://regex101.com/r/k004Gv/2if (match) {let {groups: {all, name, value}} = match
if (value !== undefined) {value = value.trim()if (value.slice(0, 1) === '"') { // stringif (value.slice(-1) !== '"') {throw new ParserError(`Parsing error: '"' expected`)}value = value.slice(1, -1)} else { // number or string (without '"')value = isNaN(Number(value)) ? String(value) : Number(value)}}
this.MoveRight(all.length)return [name, value ?? true] // If the value is undefined, then set it as ture.}throw new ParserError(`illegal format detected. ${curStr}`)}}
function ArgumentParser(str) {const obj = {}const cursor = new Cursor(str, 0)while (1) {const [name, value] = cursor.MoveToNextPara()obj[name] = valueif (cursor.pos === str.length) {return obj}}}

简单+ES6+无依赖+支持布尔标志

const process = require( 'process' );
const argv = key => {// Return true if the key exists and a value is definedif ( process.argv.includes( `--${ key }` ) ) return true;
const value = process.argv.find( element => element.startsWith( `--${ key }=` ) );
// Return null if the key does not exist and a value is not definedif ( !value ) return null;  
return value.replace( `--${ key }=` , '' );}

输出:

  • 如果用node app.js调用,那么argv('foo')将返回null
  • 如果用node app.js --foo调用,那么argv('foo')将返回true
  • 如果用node app.js --foo=调用,那么argv('foo')将返回''
  • 如果用node app.js --foo=bar调用,那么argv('foo')将返回'bar'

最初的问题是要求传递命令行参数,而不是更复杂的参数解析。然而,对于所有复杂的答案,他们都错过了一个简单、有用的变体。

您知道Unix shell支持命名参数吗?这可以追溯到1980年代的原始Bourne shell。用法很简单:

$ FOO=one BAR=two nodejs myscript.js

在Javascript中获取参数:

var foo = process.env.FOO;var bar = process.env.BAR;

命名参数更容易阅读,一旦你超过两个或三个参数。可选参数很简单,顺序不固定。

(这甚至可能在Windows上工作,最近支持Unix shell。)

此外,令人震惊的是,很少有Unix程序员知道这种用法。:)

NodeJS公开了一个名为process的全局变量。

我们可以使用:

process.argv

将命令行参数传递给我们的脚本。

process.argv的输出将是一个列表,顺序如下:

[full-path-to-node-executable,full-path-to-the-script-file...additonal-arguments-we-provide]

在节点代码中需要内置的进程库。

const {argv} = require('process')

用他们的参数运行程序。

$ node process-args.js one two=three four

Argv是下面的数组:

argv[0] = /usr/bin/nodeargv[1] = /home/user/process-args.jsargv[2] = oneargv[3] = two=threeargv[4] = four

使用最小化的npm包。这是最简单的方法,不需要担心任何事情。

const arguments = require("minimist")(process.argv.slice(2));// get the extra argument of command line .eg node app.js --process="sendEmailWithReminder"

我们也可以在Windows任务调度程序中使用它。

输入图片描述

输入图片描述

输入图片描述