Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/458.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node.js spawn:保持StdOut和StdErr的原始顺序_Javascript_Node.js_Batch File_Race Condition_Spawn - Fatal编程技术网

Javascript Node.js spawn:保持StdOut和StdErr的原始顺序

Javascript Node.js spawn:保持StdOut和StdErr的原始顺序,javascript,node.js,batch-file,race-condition,spawn,Javascript,Node.js,Batch File,Race Condition,Spawn,正在尝试从node.js v12.6.0运行windows批处理脚本,并以正确的顺序实时捕获其输出 但在测试过程中,stdout和stderr的顺序是混合的(不总是,但在80%的情况下) 如何保持stdout和stderr的原始顺序 这是我用于测试的javascript代码段: const spawn=require('child_process')。spawn; //使用“继承”修复: //“错误:不支持输入重定向,立即退出进程”。 常量选项={ 斯特迪奥:[ “inherit”,//Std

正在尝试从node.js v12.6.0运行windows批处理脚本,并以正确的顺序实时捕获其输出

但在测试过程中,stdout和stderr的顺序是混合的(不总是,但在80%的情况下)

如何保持stdout和stderr的原始顺序


这是我用于测试的javascript代码段:

const spawn=require('child_process')。spawn;
//使用“继承”修复:
//“错误:不支持输入重定向,立即退出进程”。
常量选项={
斯特迪奥:[
“inherit”,//StdIn。
'管道',//标准输出。
'pipe'//StdErr。
],
};
const child=spawn('exectest.cmd',选项);
让mergedOut='';
child.stdout.setEncoding('utf8');
child.stdout.on('data',(chunk)=>{
process.stdout.write(块);
mergedOut+=chunk;
});
child.stderr.setEncoding('utf8');
child.stderr.on('data',(chunk)=>{
process.stderr.write(块);
mergedOut+=chunk;
});
子.on('关闭',(代码,信号)=>{
console.log('-'.repeat(30));
console.log(mergedOut);
});
我已尝试使用以下命令将stderr重定向到stdout:

child.stderr.pipe(child.stdout);
并删除stderr侦听器(仅处理stdout):

child.stderr.on
为避免竞争条件,但stderr未显示在控制台中,也未添加到“mergedOut”


这是我尝试运行的批处理文件(exectest.cmd)的内容:

@Echo关闭
ChCp 65001>Nul
回声1(标准输出)。。。
回声2(标准)。。。1>&2
回声3(标准)。。。1>&2
回声4(标准输出)。。。
回声5(标准输出)。。。
回声6(标准)。。。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本身的进程stdout:

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;//很遗憾,您不能保证订购


这些是具有独立缓冲和行为的不同管道。shell本身有时会获取超出预期顺序的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

在不修改可执行文件的情况下,可接受的方法可以是(请注意,spawn选项和命令参数):

const{spawn}=require('child_进程');
常量选项={
壳牌:是的,
斯特迪奥:[
“inherit”,//StdIn。
'管道',//标准输出。
'pipe',//StdErr。
],
};
const child=spawn('exectest.cmd',['2>&1'],选项);
让mergedOut='';
child.stdout.setEncoding('utf8');
child.stdout.on('data',(chunk)=>{
process.stdout.write(chunk,(\u err)=>{});
mergedOut+=chunk;
});
子.on('关闭',(\u代码,\u信号)=>{
console.log('-'.repeat(30));
console.log(mergedOut);
});
但是,它有一些缺点:

  • 它会产生额外的控制台进程实例
  • 如果要使用“windowsHide:true”spawn options参数隐藏GUI中的应用程序,请避免使用“shell:true”参数启动进程,因为只隐藏控制台窗口,而不隐藏目标应用程序窗口
  • 无法区分StdOut和StdErr。根据目标应用程序的输出格式,此问题的解决方案可能如下所示:
  • const readline=require('readline');
    // ...
    const lineReader=readline.createInterface({
    输入:child.stdout
    });
    lineReader.on('line',(line)=>{
    if(第行包括('[错误]:')){
    console.error(行);//StdErr。
    }否则{
    console.log(行);//标准输出。
    }
    });
    
    谢谢,这是可行的,我不需要区分消息,但在这个测试批脚本中只是一个例子。我的最终目标是尝试使用node.js实现windows自动化(包括启动不同的进程和处理输出)。不幸的是,目前看来这似乎是个坏主意。是的,我在其他各种应用程序中也遇到过这个问题。尽管如此,它在某些情况下仍能可靠地工作(请参见编辑1),但随后捕获输出就成了一个问题。