Node.js 如何执行命令行二进制程序?
Node.js 执行外部程序用 child_process 模块:exec 执行简单命令拿输出,execFile 直接执行二进制(不经 shell 更安全),spawn 处理流式大输出,execSync 同步执行。本文对比四种方法与适用场景。
简单命令用 exec,执行二进制文件用 execFile(不经 shell 更安全),输出量大用 spawn,脚本里图省事用 execSync。
exec:执行 shell 命令
const { exec } = require('child_process');
exec('ls -la /tmp', (error, stdout, stderr) => {
if (error) {
console.error(`执行出错: ${error.message}`);
return;
}
console.log(`输出: ${stdout}`);
});
经 shell 执行,能用管道、重定向等 shell 特性;注意输出有 1 MiB(按字节计数,不是字符数) 默认上限(可配 maxBuffer)。
execFile:直接执行二进制(推荐)
const { execFile } = require('child_process');
execFile('/usr/bin/convert', ['input.png', '-resize', '50%', 'output.png'],
(error, stdout, stderr) => {
if (error) { console.error(error.message); return; }
console.log(stdout);
});
不经 shell,参数以数组传递——避免 shell 元字符解释,但仍可能有参数/选项注入;外部输入须按目标程序校验,支持时用 -- 结束选项,并控制可执行文件路径。
spawn:流式大输出
const { spawn } = require('child_process');
const child = spawn('ffmpeg', ['-i', 'input.mp4', 'output.webm']);
child.stdout.on('data', (data) => console.log(`输出: ${data}`));
child.stderr.on('data', (data) => console.error(`日志: ${data}`));
child.on('error', (err) => console.error(`启动失败: ${err.message}`));
child.on('close', (code) => console.log(`退出码: ${code}`));
输出按流处理,仍需及时消费并考虑背压,不能无限累积,适合长时间运行、输出量大的命令。
execSync:同步执行
const { execSync } = require('child_process');
const output = execSync('git rev-parse HEAD').toString().trim();
阻塞事件循环,只在 CLI 脚本/构建工具里用。
选型速查
| 需求 | 方法 |
|---|---|
| 简单命令拿结果 | exec |
| 执行二进制+参数来自用户 | execFile |
| 大输出/长时运行/要实时日志 | spawn |
| 脚本里同步执行 | execSync |
常见问题(FAQ)
Q:报 Error: spawn XXX ENOENT?
可能是可执行文件、脚本解释器或 cwd 不存在;检查路径和工作目录。shell: true 不能作为通用修复,会引入 shell 解析风险。
Q:exec 输出被截断?
默认 maxBuffer 是 1 MiB(按字节计数,不是字符数)。调大 exec(cmd, { maxBuffer: 10*1024*1024 }),或改用 spawn。
Q:Windows 上 .cmd/.bat 执行不了?
Windows 下批处理文件必须经 shell:spawn('npm', { shell: true }) 或用 exec。