命令行应用
command-line-apps、stdin/stdout。
35 分钟
命令行应用
Node 擅长 一次性脚本与内部 CLI:读参数、处理 stdin、写 stdout/stderr、返回退出码。本课对应 roadmap command-line-apps——在 node-runtime 的 process 基础上做完整工具。
学习目标
- 解析 argv 与子命令结构
- 处理 stdin/stdout 管道
- 包装 async main 与错误退出(衔接 nva-errors)
参数解析
轻量:手写 process.argv 或使用 Node 20+ 内置 parseArgs:
import { parseArgs } from "node:util";
const { values, positionals } = parseArgs({
options: {
dryRun: { type: "boolean", short: "n" },
file: { type: "string", short: "f" },
},
allowPositionals: true,
});
复杂子命令(import run、import validate)可引入 commander 或 yargs——nva-practice 会用到。
stdin / stdout 管道
import { createInterface } from "node:readline";
const rl = createInterface({ input: process.stdin });
for await (const line of rl) {
process.stdout.write(line.toUpperCase() + "\n");
}
Unix 哲学:CLI 只做一件事,用管道组合——例如 cat ids.txt | my-import --dry-run。
标准流与日志
| 流 | 用途 |
|---|---|
| stdout | 正常输出(可被管道消费) |
| stderr | 日志、警告、错误 message |
| exit code | CI 判断成败 |
用户-facing 进度条写 stderr,结构化结果写 stdout,便于 my-tool > out.json。
main 包装模板
export async function main(argv = process.argv.slice(2)) {
// ...
}
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch((err) => {
console.error(err.message);
process.exitCode = 1;
});
}
可测试:测试里 main(['--file', 'x.json']) 不断言 process.exit(见 test-intro 单元测试分层)。