【问题标题】:Exec : display stdout "live"执行:显示标准输出“live”
【发布时间】:2012-05-01 05:03:07
【问题描述】:

我有这个简单的脚本:

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

exec('coffee -cw my_file.coffee', function(error, stdout, stderr) {
    console.log(stdout);
});

我只是执行一个命令来编译一个咖啡脚本文件。但是 stdout 永远不会显示在控制台中,因为命令永远不会结束(因为咖啡的 -w 选项)。 如果我直接从控制台执行命令,我会收到这样的消息:

18:05:59 - compiled my_file.coffee

我的问题是:是否可以使用 node.js exec 显示这些消息?如果是怎么办? !

谢谢

【问题讨论】:

  • 我来这里是为了从 Python 可执行文件中捕获标准输出。请注意,以下所有内容都可以使用,但您需要使用“-u”选项运行 python,以使输出无缓冲,从而进行实时更新。

标签: node.js coffeescript


【解决方案1】:

这是一个用 typescript 编写的异步辅助函数,似乎对我有用。我想这对于长期存在的进程不起作用,但对某人来说仍然很方便?

import * as child_process from "child_process";

private async spawn(command: string, args: string[]): Promise<{code: number | null, result: string}> {
    return new Promise((resolve, reject) => {
        const spawn = child_process.spawn(command, args)
        let result: string
        spawn.stdout.on('data', (data: any) => {
            if (result) {
                reject(Error('Helper function does not work for long lived proccess'))
            }
            result = data.toString()
        })
        spawn.stderr.on('data', (error: any) => {
            reject(Error(error.toString()))
        })
        spawn.on('exit', code => {
            resolve({code, result})
        })
    })
}

【讨论】:

    【解决方案2】:

    我发现向执行此操作的实用程序添加自定义 exec 脚本很有帮助。

    utilities.js

    const { exec } = require('child_process')
    
    module.exports.exec = (command) => {
      const process = exec(command)
    
      process.stdout.on('data', (data) => {
        console.log('stdout: ' + data.toString())
      })
    
      process.stderr.on('data', (data) => {
        console.log('stderr: ' + data.toString())
      })
    
      process.on('exit', (code) => {
        console.log('child process exited with code ' + code.toString())
      })
    }
    

    app.js

    const { exec } = require('./utilities.js')
    
    exec('coffee -cw my_file.coffee')
    

    【讨论】:

      【解决方案3】:

      exec 还将返回一个作为 EventEmitter 的 ChildProcess 对象。

      var exec = require('child_process').exec;
      var coffeeProcess = exec('coffee -cw my_file.coffee');
      
      coffeeProcess.stdout.on('data', function(data) {
          console.log(data); 
      });
      

      pipe 子进程的标准输出到主标准输出。

      coffeeProcess.stdout.pipe(process.stdout);
      

      或使用 spawn 继承 stdio

      spawn('coffee -cw my_file.coffee', { stdio: 'inherit' });
      

      【讨论】:

      • 看起来这可以通过使用pipe来简化:coffeeProcess.stdout.pipe(process.stdout);
      • @EricFreese 的评论正是我想要的,因为我想利用标准输出的字符替换功能(在节点脚本中使用量角器)
      • 更简单:spawn(cmd, argv, { stdio: 'inherit' })。有关不同的示例,请参见 nodejs.org/api/child_process.html#child_process_options_stdio
      • +1 表示@MorganTouvreyQuilling 建议使用spawnstdio: 'inherit'。它产生比exec 和管道stdout/stderr 更准确的输出,例如在显示来自git clone 的进度信息时。
      【解决方案4】:

      child_process.spawn 返回一个带有 stdout 和 stderr 流的对象。 您可以点击 stdout 流来读取子进程发送回 Node.js 的数据。作为流的标准输出具有流具有的“数据”、“结束”和其他事件。 spawn 最适合用于希望子进程向 Node 返回大量数据的情况——图像处理、读取二进制数据等。

      这样您就可以使用下面使用的 child_process.spawn 来解决您的问题。

      var spawn = require('child_process').spawn,
      ls = spawn('coffee -cw my_file.coffee');
      
      ls.stdout.on('data', function (data) {
        console.log('stdout: ' + data.toString());
      });
      
      ls.stderr.on('data', function (data) {
        console.log('stderr: ' + data.toString());
      });
      
      ls.on('exit', function (code) {
        console.log('code ' + code.toString());
      });
      

      【讨论】:

        【解决方案5】:

        已经有几个答案,但是没有一个提到最好(也是最简单)的方法,即使用spawn{ stdio: 'inherit' } option。它似乎产生了最准确的输出,例如在显示来自git clone 的进度信息时。

        只需这样做:

        var spawn = require('child_process').spawn;
        
        spawn('coffee', ['-cw', 'my_file.coffee'], { stdio: 'inherit' });
        

        感谢@MorganTouvreyQuilling 在this comment 中指出这一点。

        【讨论】:

        • 我发现当子进程使用彩色文本等格式化输出时,stdio: "inherit" 会保留该格式,而child.stdout.pipe(process.stdout) 不会。
        • 即使在具有复杂输出的进程(例如 npm 安装上的进度条)上,它也能完美地保留输出。太棒了!
        • 为什么这不是公认的答案?它是唯一对我有用的,它只有 2 条 f* 线!!!
        • 这个技巧在执行一些使用进度条的 Symfony 命令行应用程序时很有帮助。干杯。
        • 这应该是公认的答案——只有保留完美输出表示的东西并且它是最简单的?是的,请
        【解决方案6】:

        不要使用exec。使用 spawn 这是一个 EventEmmiter 对象。然后您可以收听 stdout/stderr 事件 (spawn.stdout.on('data',callback..))发生时

        来自 NodeJS 文档:

        var spawn = require('child_process').spawn,
            ls    = spawn('ls', ['-lh', '/usr']);
        
        ls.stdout.on('data', function (data) {
          console.log('stdout: ' + data.toString());
        });
        
        ls.stderr.on('data', function (data) {
          console.log('stderr: ' + data.toString());
        });
        
        ls.on('exit', function (code) {
          console.log('child process exited with code ' + code.toString());
        });
        

        exec 缓冲输出,通常在命令执行完成后返回。

        【讨论】:

        • 非常好。仅供参考:stdout/stderr 事件回调参数“数据”是一个缓冲区,所以用 .toString() 调用它
        • 对于那些无法在 Windows 上工作的人来说,看看这个很棒的 answer
        • exec 至少最近也是一个 EventEmitter。
        • 还请记住,只要程序输出换行符,就不会调用回调。如果您想从子进程接收“事件”,该进程必须刷新缓冲区(C 中的flush(stdout);)才能在 Node.js 中触发事件。
        • +1 on exec 也是一个 EventEmitter.. 花了 2 个小时将我的字符串重构为一个 args 数组(非常长且复杂的 ffmpeg 命令行).. 才发现我真的不需要到。
        【解决方案7】:

        在查看了所有其他答案后,我得出了以下结论:

        function oldSchoolMakeBuild(cb) {
            var makeProcess = exec('make -C ./oldSchoolMakeBuild',
                 function (error, stdout, stderr) {
                     stderr && console.error(stderr);
                     cb(error);
                });
            makeProcess.stdout.on('data', function(data) {
                process.stdout.write('oldSchoolMakeBuild: '+ data);
            });
        }
        

        有时data 将是多行,因此oldSchoolMakeBuild 标题将出现一次多行。但这并没有让我烦恼到足以改变它。

        【讨论】:

          【解决方案8】:

          受到 Nathanael Smith 的回答和 Eric Freese 的评论的启发,它可能很简单:

          var exec = require('child_process').exec;
          exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);
          

          【讨论】:

          • 这对于像ls 这样的简单命令似乎工作得很好,但对于像npm install 这样的更复杂的命令就失败了。我什至尝试将 stdout 和 stderr 都通过管道传输到它们各自的进程对象。
          • @linuxdan 可能是因为 npm 在 stderr 中写入(我看到有人在那里写进度条)。您还可以通过管道传输 stderr,或扩展通发解决方案以在 stderr 上侦听。
          • @linuxdan 我见过最可靠的方法是spawn(command, args, { stdio: 'inherit' }),这里建议stackoverflow.com/questions/10232192/…
          • 最佳答案,谢谢。像魅力一样工作
          【解决方案9】:

          我想补充一点,使用console.log() 从生成的进程输出缓冲区字符串的一个小问题是它添加了换行符,这可以将生成的进程输出分散到其他行上。如果您使用process.stdout.write() 而不是console.log() 输出stdoutstderr,那么您将“按原样”从生成的进程获得控制台输出。

          我在这里看到了该解决方案: Node.js: printing to console without a trailing newline?

          希望对使用上述解决方案的人有所帮助(这对于实时输出来说是一个很好的解决方案,即使它来自文档)。

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-12-20
          • 1970-01-01
          • 2021-08-09
          • 1970-01-01
          • 2015-03-16
          相关资源
          最近更新 更多