nodejs的child_process可以直接用于执行命令,利用spawn轻松通过stdout, stderr获取输出的内容。但是,在获取内容时,有一个不好的地方,stdout, stderr输出的内容是以流的形式,需要通过监听data来读取流式输出,而这个过程中,它的输出可能比较随机,断句并不一定是某条命令行语句执行后的完整输出,而可能是命令行中到一定时间就输出,这个时候就会造成断句混乱:
const { spawn } = require('child_process') const child = spawn('npm', ['install', '--verbose'], { cwd: process.cwd() }) child.stdout.on('data', fn) child.stderr.on('data', fn)
function fn(data) {
console.log(data.toString())
}
这就比较麻烦,界面上显示的内容错位了。解决的办法是什么呢?其实你不要用console.log,而是要自己写一个输出逻辑,两个流并行,对于stdout输出的内容直接连接到上一个输出的就可以了。另外写一个流,当有新的内容被加入的时候,通过触发一个函数,检查内容的最后一个\r\n,然后在这里截断,把前面的内容输出即可。
下面是我实现的一个函数:
export function execute(cmd, callback, cwd = process.cwd()) { return new Promise((resolve, reject) => { let items = cmd.split(' ') let exe = items.shift() let processor = spawn(exe, items, { cwd }) let collect = () => { let str = '' let print = () => { let lines = str.split(/[\n|\r\n]/) str = lines.pop() let contents = lines.join('\r\n') if (str === '') { // 如果本来内容就是完整断句的,这里进行修正,表示结尾是正常断句的 contents += '\r\n' } callback(contents) } return (data) => { str += data.toString() print() } } if (typeof callback === 'function') { processor.stdout.on('data', collect()) processor.stderr.on('data', collect()) } processor.on('error', reject) processor.on('close', resolve) }) }
用法很简单
await execute('npm install --verbose', (contents) => console.log(contents))
这样,用console.log打印的内容,就不会出现断句不正常的问题了。
2018-10-17 7906 child_process, 命令行