【问题标题】:Cannot pipe stdout from spawn for a specific application无法从 spawn 为特定应用程序管道 stdout
【发布时间】:2017-06-03 13:26:50
【问题描述】:

我有两个脚本 A.js 和 B.js,以及一个 3rd 方应用程序(它是开源的)。脚本 A.js 使用 execSync 启动第 3 方应用程序。脚本 B.js 使用 spawn 启动脚本 A.js。

如果我自己运行脚本 A.js,我可以看到第 3 方应用程序的整个输出。当我通过运行脚本B.js间接运行它时,我只能看到一些输出。

A.js

const { execSync } = require('child_process');
console.log("Hello");
execSync('mybinary.exe -arg1 -arg2', { stdio: 'inherit' });

B.js

const { spawn } = require('child_process');
const app = spawn(process.execPath, ['A.js'], {
  stdio: ['inherit', null, 'inherit']
});

app.stdout.on('data', (chunk) => {
  process.stdout.write(chunk);
});

当我启动 B 时,我只看到“Hello”,但是二进制 正在 运行(它是一个服务器,我可以打开一个到它的 TCP 连接)。我只是没有看到输出。当我自己启动 A 时,我会看到“Hello”和常规二进制文件的输出。

如果我将 B 的标准输出更改为“继承”,它会起作用。

为什么会发生这种情况,我该如何解决?

更新:似乎与使用两个脚本没有任何关系。在不使用 stdio 继承的情况下直接生成二进制文件会出现同样的问题。似乎依赖于第三方应用程序。 如果程序只是打印到标准输出,它会如何影响节点?

上下文:我想启动一个服务器,然后在服务器准备好时运行一个命令。准备就绪后,服务器会打印出特定消息。这个想法是等待这条消息被打印出来。打印出这条消息后,它不会打印出任何其他内容,而是继续运行。

我试图通过管道传输的特定可执行文件是 ChatScript server

更新:在这一点上,我假设它与我正在尝试传输的特定二进制文件有关。我想了解二进制文件如何影响这种行为,即使用继承而不是管道。 如果有人可以使用节点脚本(或 c 程序)重新创建此行为,那将回答这个问题。


环境

  • 操作系统:Windows 10
  • 控制台:Cygwin(也尝试了常规命令提示符)。
  • 节点 v7.10.0

请注意,这与此处的问题相同:node.js child_process.spawn no stdout unless 'inherit'

【问题讨论】:

    标签: node.js process spawn


    【解决方案1】:

    chatscript 正在执行的写入是 'fprintf(stdout, ...)' 这是一个缓冲输出,并保存到类似 (4k?) 被缓冲然后刷新。例如,在 ChatScript/src/os.cpp 第 1849 行中的 fprintf(stdout) 之后添加“fflush(stdout)”......然后输出工作(在某种程度上,需要进一步的更改,但我确实得到了至少 'in cs_init. txt' 错误现在记录。

    另一个测试只是将 chatscript.exe 重定向到一个文件并查看该文件得到了什么。 'chatscript > zz' 然后用 ctrl-c 结束 chatscript 你会看到 zz 也是空白的……这表明 IO 已被缓冲并且没有被刷新以适当地输出。

    M:\javascript\test_exec>node b.js
    Hello
    
       in cs_init.txt at 0:
         A subdirectory or file USERS already exists.
    Error opening utf8writeappend file LOGS/startlog.txt: No such file or     directory
    ChatScript Release Version 7.5 pid: 0 32 bit Windows compiled Jun 24 2017 09:42:13 host=local
    Params:   dict:2097151 fact:800000 text:100000kb hash:215127
              buffer:80x80kb cache:1x5000kb userfacts:100 outputlimit:80000     loglimit:80000
    Unable to read dictionarySystem.h
    Missing 37 word files
    read 0 raw words
    
       in facts.txt at 0:
        A subdirectory or file USERS already exists.
    

    【讨论】:

    • 我感觉这就是问题所在。你知道为什么直接运行聊天脚本(在节点外)会“正确”打印标准输出吗? ttys 是否设置了某种标志来禁用(或降低)缓冲?你会在一个简单的 windows cmd 中看到它在节点之外打印正常。
    【解决方案2】:

    有一个简单而安全的解决方法是将应用程序的输出通过管道传输到一个文件,然后从同一个文件中读取它,因此您不必担心在您尝试之前或之后是否触发了事件去听吧。

    管道到文件:

    var fs = require('fs');
    var spawn = require('child_process').spawn;
    var out = fs.openSync('./out.log', 'a');
    var err = fs.openSync('./err.log', 'a');
    
    var child = spawn('applicaiton', [], {
        detached: true,
        stdio: [ 'ignore', out, err ]
    });
    

    希望对你有帮助,告诉我进展如何;

    祝你好运,

    【讨论】:

    • 没用。当 detached 为真(用shell: trueshell:false 测试)时,不会将输出写入文件。当 detached 为 false 时,只写入部分输出,就像我输入原始问题时一样。作为旁注,当 detached 为真(并且 shell 为真)并且文件没有输出时,我可以在屏幕上出现的新分离 shell 中看到正确的输出。我无法捕获该输出。
    猜你喜欢
    • 2019-07-04
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 2020-09-26
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    相关资源
    最近更新 更多