Node.js调用spawn/exec执行Bash命令遇ENOENT错误问题
问题背景
在Debian 10(GNU bash 5.0.3)系统中,以下Bash命令在终端直接粘贴可正常执行:
documents=("/data/sice.pdf" "/das00/12ser.pdf");bash ./clean-pdfs.sh "${documents[*]}"
但使用Node.js的exec或spawn调用该命令时均失败:
- 使用
exec时出现括号相关报错 - 改用
spawn后,出现无明确指向的ENOENT错误
相关Node.js代码:
const { exec } = require('child_process'); command = `documents=(${pdfPaths});` + 'bash ./clean-pdfs.sh "${documents[*]}"' console.log(command); const subProcess = require('child_process') const lsChildProcess = subProcess.spawn(command) lsChildProcess.stdout.on('data', (data) => { console.log(data); }) lsChildProcess.on('error', function(err) { console.log(err); });
运行后得到的错误信息:
{ Error: spawn documents=("/data/Traa.pdf" "/dater.pdf");bash ./clean-pdfs.sh "${documents[*]}" ENOENT at Process.ChildProcess._handle.onexit (internal/child_process.js:240:19) at onErrorNT (internal/child_process.js:415:16) at process._tickCallback (internal/process/next_tick.js:63:19) errno: 'ENOENT', code: 'ENOENT', syscall: 'spawn documents=("/daice.pdf" "/daer.pdf");bash ./clean-pdfs.sh "${documents[*]}"', path: 'documents=("/dace.pdf" "/daer.pdf");bash ./clean-pdfs.sh "${documents[*]}"', spawnargs: [] }
错误原因
spawn方法的工作逻辑是直接调用系统中的可执行文件,而非像终端那样通过shell解析命令字符串。你传入的整个命令串并不是系统中存在的可执行程序,因此触发ENOENT(找不到指定文件/程序)错误。
解决方案
方案1:正确使用spawn调用shell命令
将bash作为可执行程序传入,通过-c参数让bash执行你的完整命令串:
const { spawn } = require('child_process'); // 假设pdfPaths是已处理好的带引号的路径字符串,或直接传入数组转义后的格式 const pdfPaths = '"/data/Traa.pdf" "/dater.pdf"'; const lsChildProcess = spawn('bash', [ '-c', `documents=(${pdfPaths}); bash ./clean-pdfs.sh "${documents[*]}"` ]); // 处理标准输出 lsChildProcess.stdout.on('data', (data) => { console.log(data.toString()); }); // 处理错误输出 lsChildProcess.stderr.on('data', (data) => { console.error(data.toString()); }); lsChildProcess.on('error', (err) => { console.error(err); });
方案2:修正exec的写法
exec默认会通过shell解析命令,之前的报错是因为路径字符串的转义问题。需要确保路径数组被正确转成bash可识别的格式:
const { exec } = require('child_process'); const pdfPathsArray = ["/data/Traa.pdf", "/dater.pdf"]; // 转义路径中的引号,确保bash能正确解析 const formattedPaths = pdfPathsArray .map(path => `"${path.replace(/"/g, '\\"')}"`) .join(' '); const command = `documents=(${formattedPaths}); bash ./clean-pdfs.sh "${documents[*]}"`; exec(command, (error, stdout, stderr) => { if (error) { console.error(`执行错误: ${error.message}`); return; } console.log(`输出: ${stdout}`); if (stderr) { console.error(`错误输出: ${stderr}`); } });
方案3:简化调用(推荐)
无需在shell中定义数组,直接将路径作为参数传给clean-pdfs.sh,Node.js的数组展开语法可直接传递多个参数:
const { spawn } = require('child_process'); const pdfPaths = ["/data/Traa.pdf", "/dater.pdf"]; // 直接将路径作为脚本参数传入 const lsChildProcess = spawn('bash', ['./clean-pdfs.sh', ...pdfPaths]); lsChildProcess.stdout.on('data', (data) => console.log(data.toString())); lsChildProcess.stderr.on('data', (data) => console.error(data.toString())); lsChildProcess.on('error', (err) => console.error(err));
此时在clean-pdfs.sh中可通过$@获取所有传入的路径参数。
内容的提问来源于stack exchange,提问作者abbb
相关产品推荐
相关产品推荐

