Menu

Node.js process.argv:读取命令行参数

process.argv 是一个数组,保存着启动你程序的那条命令行:node 可执行文件、脚本路径,然后是你输入的每个参数。用 process.argv.slice(2) 就能只拿到你自己的参数。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

process.argv 是一个数组,保存着启动你的 Node.js 程序的那条命令行。索引 0 是 node 可执行文件的路径,索引 1 是你的脚本路径,你自己的参数从索引 2 开始。所以 process.argv.slice(2) 得到的正好是用户在文件名之后输入的内容,而且总是字符串。

前两项是完整路径,所以这里只打印它们的最后一部分(node 和 index.js),然后是 [ 'Ada', '42', '--verbose' ]。把“参数”一栏改成 Grace 7 再运行一次:数组也会跟着变。

process.argv 里有什么

shell 会把 node 之后的那一行按空格拆开,再把这些片段交给 Node.js。写在文件名之前的标志属于 Node.js 本身,而不属于你的程序:

node --max-old-space-size=4096 index.js --port=8080
# process.argv.slice(2) is [ '--port=8080' ]
# process.execArgv is      [ '--max-old-space-size=4096' ]

引号可以把多个单词合成一个参数("Ada Lovelace" 会作为一个字符串传进来),而像 *.txt 这样的模式,在 Node.js 看到之前就已经被 shell 展开成文件名了。

用 slice(2) 获取参数

大多数脚本会对预期的参数做解构,并给每个参数一个默认值:

它打印了 Hello, Ada:一个参数填进了 name,greeting 则使用了默认值。在“参数”一栏中的 Ada 后面加上 Hi,它就会打印 Hi, Ada;清空这一栏,你会得到 Hello, world。

数字以字符串形式传入

shell 没有类型。每个参数都是字符串,所以在转换之前对它们做算术运算会出错:

a + b 把两个字符串拼成了 75,而 Number() 得到了 12。不是数字的单词会变成 NaN,所以要用 Number.isNaN 检查,并打印一条用法说明,而不是带着一个错误的值继续运行。

手动解析 --name=value 标志

如果只有几个标志,一个简短的循环就够了。下面这个循环把 --port=8080 变成 port: '8080',把单独的 --verbose 变成 true,其他内容都作为位置参数保留:

它打印了 {"port":"8080","verbose":true} 和 [ 'build', 'src' ],其中 port 仍然是字符串。这个循环处理不了 -p 这样的短标志,也处理不了值写在下一个参数里的情况(--port 8080);这些情况请使用下面的内置解析器。

util.parseArgs:内置的解析器

Node.js 18.3 及以上版本自带 util.parseArgs,它能处理长标志和短标志、写在下一个参数里的值、布尔值和默认值:

const { parseArgs } = require('node:util');

// node index.js -p 8080 --verbose src
const { values, positionals } = parseArgs({
    options: {
        port: { type: 'string', short: 'p', default: '3000' },
        verbose: { type: 'boolean', short: 'v' },
    },
    allowPositionals: true,
});

console.log(values);      // [Object: null prototype] { port: '8080', verbose: true }
console.log(positionals); // [ 'src' ]

parseArgs 默认读取 process.argv.slice(2)。遇到你没有声明的选项时它会抛出错误,这样就能发现 --prot 这样的拼写错误;传入 strict: false 可以接受未知标志。选项类型只有 string 和 boolean,所以数字仍然需要 Number() 转换。values 是一个没有原型的对象,所以打印时会带有 [Object: null prototype];像读取普通对象一样读取它即可。

常见错误

把 process.argv[0] 当作第一个参数。 它是 node 的路径。你的第一个参数是 process.argv[2]。

忘了一切都是字符串。 '10' > '9' 是 false,因为字符串是逐个字符比较的。先转换类型。

把机密信息放在参数里。 命令行会出现在 shell 历史记录中,也会出现在这台机器上其他用户能看到的进程列表里。密码和 API 密钥要改用环境变量传递。

常见问题

如何给 npm 脚本传参数?

把参数写在 -- 之后:npm run start -- --port=4000。npm 会把 -- 之后的所有内容传给你的脚本,它们会出现在 process.argv.slice(2) 中。

为什么 process.argv[2] 是 undefined?

因为启动程序时没有传这个参数。给它一个默认值(process.argv[2] ?? 'guest'),或者打印一行用法说明,然后用 process.exit(1) 退出。

应该用 yargs 或 commander 代替 process.argv 吗?

对于只有几个标志的脚本,内置的 util.parseArgs 就够了。commander 和 yargs 这类包增加了帮助文本、子命令和参数校验,当你的工具有好几个命令时就值得使用。

Coddy 编程语言插图

和 Coddy 一起学编程

开始