Node.js child_process exec 的标准输出被缩短

Posted

技术标签:

【中文标题】Node.js child_process exec 的标准输出被缩短【英文标题】:Stdout of Node.js child_process exec is cut short 【发布时间】:2014-02-06 22:56:04 【问题描述】:

在 Node.js 中,我使用 child_process 模块的 exec 命令调用 Java 中的算法,该算法将大量文本返回到标准输出,然后我对其进行解析和使用。大部分我都能捕捉到,但是当它超过一定的行数时,内容就会被截断。

exec("sh target/bin/solver "+fields.dimx+" "+fields.dimy, function(error, stdout, stderr)
    //do stuff with stdout

我尝试过使用 setTimeouts 和回调,但没有成功,但我确实觉得这种情况正在发生,因为我在代码中引用了标准输出,然后才能完全检索它。我已经测试过 stdout 实际上是第一次发生数据丢失的地方。这不是进一步的异步问题。我也在我的本地机器和 Heroku 上对此进行了测试,并且发生了完全相同的问题,每次都在完全相同的行号处截断。

您有什么想法或建议可以对此有所帮助吗?

【问题讨论】:

另见:Stdout buffer issue using node child_process 【参考方案1】:

我让 exec.stdout.on('end') 回调永远挂在 @damphat 解决方案中。

另一种解决方案是在 exec 的选项中增加缓冲区大小:参见文档here

 encoding: 'utf8',
  timeout: 0,
  maxBuffer: 200*1024, //increase here
  killSignal: 'SIGTERM',
  cwd: null,
  env: null 

引用:maxBuffer 指定 stdout 或 stderr 上允许的最大数据量 - 如果超过此值,则子进程将被终止。我现在使用以下内容:这不需要处理标准输出中由逗号分隔的块的分隔部分,而不是接受的解决方案。

exec('dir /b /O-D ^2014*', 
    maxBuffer: 2000 * 1024 //quick fix
    , function(error, stdout, stderr) 
        list_of_filenames = stdout.split('\r\n'); //adapt to your line ending char
        console.log("Found %s files in the replay folder", list_of_filenames.length)
    
);

【讨论】:

【参考方案2】:

这个问题的真正(也是最好的)解决方案是使用 spawn 而不是 exec。 如in this article 所述,spawn 更适合处理大量数据:

child_process.exec 返回子进程的整个缓冲区输出。默认情况下,缓冲区大小设置为 200k。如果子进程返回的内容不止于此,您的程序将崩溃并显示错误消息“错误:超出最大缓冲区”。您可以通过在 exec 选项中设置更大的缓冲区大小来解决该问题。但是您不应该这样做,因为 exec 不适用于将 HUGE 缓冲区返回给 Node 的进程。你应该使用 spawn 。那么你用 exec 做什么呢?使用它来运行返回结果状态而不是数据的程序。

spawn 需要与 exec 不同的语法:

var proc = spawn('sh', ['target/bin/solver', 'fields.dimx', 'fields.dimy']);

proc.on("exit", function(exitCode) 
    console.log('process exited with code ' + exitCode);
);

proc.stdout.on("data", function(chunk) 
    console.log('received chunk ' + chunk);
);

proc.stdout.on("end", function() 
    console.log("finished collecting data chunks from stdout");
);

【讨论】:

感谢您的回答!它帮助我了解我的 exec 由于 1MB 的输出而返回错误。不幸的是,exec 的错误对象只返回了命令名称,而没有详细说明错误原因:"cmd":"./read_mail.sh"【参考方案3】:

编辑: 我在我的电脑(windows)上尝试了dir /s 并遇到了同样的问题(它看起来像一个错误),这段代码为我解决了这个问题:

var exec = require('child_process').exec;

function my_exec(command, callback) 
    var proc = exec(command);

    var list = [];
    proc.stdout.setEncoding('utf8');

    proc.stdout.on('data', function (chunk) 
        list.push(chunk);
    );

    proc.stdout.on('end', function () 
        callback(list.join());
    );


my_exec('dir /s', function (stdout) 
    console.log(stdout);
)

【讨论】:

为什么你认为它看起来像一个错误?请看我的回答 @olamotte 你可以看到这个答案的历史,我增加了缓冲区大小,但它对我不起作用。

以上是关于Node.js child_process exec 的标准输出被缩短的主要内容,如果未能解决你的问题,请参考以下文章

node.js 安全/转义中的 child_process 生成

如何在 Node.JS 中获取生成的 child_process 的输出?

如何模拟 Node.js child_process spawn 函数?

Node.js child_process exec 的标准输出被缩短

[Node] 如何使用 VSCode 调试 child_process

进程替换 - Node.js child_process