![](/img/trans.png)
[英]Defining stdout and stderr in a child.process in node.js 8
[英]Node.js spawn: Keep StdOut and StdErr in the original order
尝试从 node.js v12.6.0 运行 Windows 批处理脚本并以正确的顺序实时捕获其输出。
但是 stdout 和 stderr 的顺序在测试期间是混合的(并非总是如此,但在 80% 的情况下)。
如何保持标准输出和标准错误的原始顺序?
这是我用于测试的 javascript 片段:
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 重定向到 stdout:
child.stderr.pipe(child.stdout);
并删除 stderr 侦听器(仅处理 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);
为了避免在“数据”回调中引用“进程”,排序也会中断。
在不修改可执行文件的情况下,可接受的方法是(注意 spawn 选项和命令参数):
const { spawn } = require('child_process');
const options = {
shell: true,
stdio: [
'inherit', // StdIn.
'pipe', // StdOut.
'pipe', // StdErr.
],
};
const child = spawn('exectest.cmd', ['2>&1'], options);
let mergedOut = '';
child.stdout.setEncoding('utf8');
child.stdout.on('data', (chunk) => {
process.stdout.write(chunk, (_err) => { });
mergedOut += chunk;
});
child.on('close', (_code, _signal) => {
console.log('-'.repeat(30));
console.log(mergedOut);
});
但是,它有一些缺点:
const readline = require('readline');
// ...
const lineReader = readline.createInterface({
input: child.stdout
});
lineReader.on('line', (line) => {
if (line.includes('[ERROR]:')) {
console.error(line); // StdErr.
} else {
console.log(line); // StdOut.
}
});
不幸的是,您不能保证订购。
这些是具有独立缓冲和行为的不同管道。 外壳本身有时会以不符合预期顺序的方式获取 STDERR/STDOUT 消息。 这也是其他应用程序的典型特征,甚至在 Node.js 之外也是如此。
如果不需要区分 STDOUT 和 STDERR,可以在源头(批处理文件内)加入它们。 然后批处理文件将所有 STDERR 和 STDOUT 仅作为 STDOUT 返回
@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
) 2>&1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.