【发布时间】:2019-07-15 20:42:10
【问题描述】:
尝试从 node.js v12.6.0 运行 windows 批处理脚本并以正确的顺序实时捕获其输出。
但在测试过程中,stdout 和 stderr 的顺序经常(并非总是如此,但在 80% 的情况下)是混合的。
如何让stdout和stderr保持原来的顺序?
这是我用于测试的 javascript sn-p:
const spawn = require('child_process').spawn;
// Using 'inherit' to fix:
// "ERROR: Input redirection is not supported, exiting the process immediately".
const options = {
stdio: [
'inherit', // StdIn.
'pipe', // StdOut.
'pipe' // StdErr.
],
};
const child = spawn('exectest.cmd', options);
let mergedOut = '';
child.stdout.setEncoding('utf8');
child.stdout.on('data', (chunk) => {
process.stdout.write(chunk);
mergedOut += chunk;
});
child.stderr.setEncoding('utf8');
child.stderr.on('data', (chunk) => {
process.stderr.write(chunk);
mergedOut += chunk;
});
child.on('close', (code, signal) => {
console.log('-'.repeat(30));
console.log(mergedOut);
});
我尝试将 stderr 重定向到标准输出:
child.stderr.pipe(child.stdout);
并移除标准错误监听器(仅处理标准输出):
child.stderr.on
为了避免竞争条件,但 stderr 未显示在控制台中,也未添加到“mergedOut”中。
这是我尝试运行的批处理文件 (exectest.cmd) 的内容:
@Echo Off
ChCp 65001 >Nul
Echo 1 (stdout) ...
Echo 2 (stderr) ... 1>&2
Echo 3 (stderr) ... 1>&2
Echo 4 (stdout) ...
Echo 5 (stdout) ...
Echo 6 (stderr) ... 1>&2
当前输出:
1 (stdout) ...
2 (stderr) ...
3 (stderr) ...
6 (stderr) ...
4 (stdout) ...
5 (stdout) ...
------------------------------
1 (stdout) ...
2 (stderr) ...
3 (stderr) ...
6 (stderr) ...
4 (stdout) ...
5 (stdout) ...
预期输出:
1 (stdout) ...
2 (stderr) ...
3 (stderr) ...
4 (stdout) ...
5 (stdout) ...
6 (stderr) ...
------------------------------
1 (stdout) ...
2 (stderr) ...
3 (stderr) ...
4 (stdout) ...
5 (stdout) ...
6 (stderr) ...
编辑 1:
与:
stdio: [
'inherit', // StdIn.
'inherit', // StdOut.
'inherit' // StdErr.
],
输出顺序确实正确,因此 node.js 本身似乎“知道” 如何正确地做到这一点。
但是在这种情况下,我不知道如何捕获输出:
child.stdout
为'null',并尝试监听node.js本身的进程标准输出:
process.stdout.on('data' ...)
在任何配置中都会给出“错误:读取 ENOTCONN”。
编辑 2:
如果合并流并以这种方式收听:
const mergedStream = child.stdout.wrap(child.stderr);
mergedStream.on('data' ...);
我们对 stdout 和 stderr 都有一个侦听器,但排序仍然中断。
编辑 3:
如果您想捕获输出或显示它,是否可以保持正确的顺序。
要显示正确的输出而不捕获它,请参阅“编辑 1”。
要捕获正确的输出而不实时显示,只需使用:
child.stdout.on('data', (chunk) => {
mergedOut += chunk;
});
child.stderr.on('data', (chunk) => {
mergedOut += chunk;
});
但是,一旦您尝试在以下内容中引用“process.stdout / process.stderr”:
child.stdout.on('data' ...)
回调,排序将中断。
例如:
child.stdout.on('data', (chunk) => {
process.stdout; // <-- This line will break everything.
// You do not even need to .write() to it!
});
或者如果你尝试:
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
为了避免在“数据”回调中引用“进程”, 订单也会中断。
【问题讨论】:
标签: javascript node.js batch-file race-condition spawn