执行:显示标准输出“live”

Posted

技术标签:

【中文标题】执行:显示标准输出“live”【英文标题】:Exec : display stdout "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,以使输出无缓冲,从而进行实时更新。 【参考方案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' ),这里建议***.com/questions/10232192/… 最佳答案,谢谢。像魅力一样工作【参考方案9】:

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

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

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

【讨论】:

要获得更准确的输出,请使用spawn(command, args, stdio: 'inherit' ),正如@MorganTouvreyQuilling 在此处***.com/questions/10232192/… 所建议的那样@

以上是关于执行:显示标准输出“live”的主要内容,如果未能解决你的问题,请参考以下文章

C编译二进制文件的Nodejs exec在标准输出上显示标准错误?

重定向与管道

重定向标准输入/输出

在linux上单独执行屏幕有输出,重定向后没有任何输出了。 myprog > 1.log 或 myprog tee 1.log

如何在 C 中覆盖标准输出

夺命雷公狗---linux NO:13 linux标准输入输出和标准错误