Node.js使用child_process获取zsh子进程完整输出问题
捕获zsh中read命令的提示输出问题
我用Node.js的child_process.spawn启动zsh子进程,执行带提示的read命令时,无法捕获到name?的提示信息,仅能看到最终的done输出,但输入内容能正确写入文件。
我的代码
const { spawn } = require('child_process'); let child; async function executeCommandOrSendInput(commandOrInput) { if (!child || child.exitCode !== null) { console.log('Creating new child process'); child = spawn('zsh', [], { stdio: 'pipe' }); child.stdout.on('data', (data) => { console.log(`Output: ${data}`); }); child.stderr.on('data', (data) => { console.error(`Error: ${data}`); }); child.on('close', (code) => { console.log(`Child process exited with code ${code}`); }); } console.log('Sending command or input:', commandOrInput); child.stdin.write(commandOrInput + '\n'); } (async () => { try { await executeCommandOrSendInput('read "name?name?" ;echo $name > /tmp/thename.txt; echo done'); await new Promise(resolve => setTimeout(resolve, 1000)); await executeCommandOrSendInput('my_name'); await new Promise(resolve => setTimeout(resolve, 1000)); child.stdin.end(); } catch (error) { console.error('An error occurred:', error); } })();
当前输出
Creating new child process Sending command or input: read "name?name?" ;echo $name > /tmp/thename.txt; echo done Sending command or input: my_name Output: done Child process exited with code 0
解决方法
原因分析
zsh的read命令默认将提示信息输出到标准错误流(stderr),而非stdout;同时非交互式模式下的zsh会调整部分命令行为,导致提示输出逻辑变化。
方案1:监听stderr获取提示
修改stderr的处理逻辑,直接打印输出(因为提示属于正常输出,并非错误):
child.stderr.on('data', (data) => { console.log(`Prompt: ${data}`); });
运行后就能捕获到name?的提示信息。
方案2:启动交互式zsh
启动zsh时添加-i参数强制进入交互式模式,确保命令行为与终端环境一致:
child = spawn('zsh', ['-i'], { stdio: 'pipe' });
结合方案1的stderr监听,即可正常捕获提示。
方案3:将提示重定向到stdout
修改执行的命令,把read的提示输出重定向到stdout:
read "name?name?" 2>&1 ;echo $name > /tmp/thename.txt; echo done
这样提示会被现有stdout监听到,无需修改代码的监听逻辑。
内容的提问来源于stack exchange,提问作者umop
相关产品推荐
相关产品推荐

