执行:显示标准输出"直播"

Tre*_*xXx 154 node.js coffeescript

我有这个简单的脚本:

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

exec('coffee -cw my_file.coffee', function(error, stdout, stderr) {
    console.log(stdout);
});
Run Code Online (Sandbox Code Playgroud)

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

18:05:59 - compiled my_file.coffee
Run Code Online (Sandbox Code Playgroud)

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

谢谢

Poo*_*imi 236

不要用exec.使用spawn哪个是EventEmmiter对象.然后你可以听到stdout/ stderrevents(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());
});
Run Code Online (Sandbox Code Playgroud)

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

  • 非常好.仅供参考:stdout/stderr事件回调参数'data'是一个缓冲区,所以用.toString()调用它 (19认同)
  • exec至少在最近也是一个EventEmitter. (15认同)
  • exec上的+1也是一个EventEmitter ..花了2个小时将我的字符串重构为一个args数组(非常漫长而复杂的ffmpeg命令行)..但却发现我并不是真的需要. (5认同)
  • 对于那些无法在Windows上工作的人,请看看这个伟大的[答案](http://stackoverflow.com/a/17537559/2816199). (3认同)
  • 还要记住,只要程序输出换行符,就不会调用回调.如果你想从子进程接收"事件",这个进程必须刷新缓冲区(`C中的`flush(stdout);`),以便在Node.js中触发事件. (2认同)
  • 对我来说,发现 `process.stdout.write( data.toString() );` 可以防止在每次 stdout 发射后添加换行符(就像 console.log 那样),这对我很有帮助。 (2认同)

Nat*_*ith 151

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); 
});
Run Code Online (Sandbox Code Playgroud)

或者pipe子进程的stdout到主stdout.

coffeeProcess.stdout.pipe(process.stdout);
Run Code Online (Sandbox Code Playgroud)

或者使用spawn继承stdio

spawn('coffee -cw my_file.coffee', { stdio: 'inherit' });
Run Code Online (Sandbox Code Playgroud)

  • 看起来这可以通过使用`pipe`简化:`coffeeProcess.stdout.pipe(process.stdout);` (32认同)
  • 更简单:`spawn(cmd,argv,{stdio:'inherit'})`.有关不同的示例,请参阅https://nodejs.org/api/child_process.html#child_process_options_stdio. (14认同)
  • @ EricFreese的评论是我想要的,因为我想利用stdout的字符替换功能(在节点脚本中利用量角器) (3认同)
  • @ MorganTouvereyQuilling建议使用`spawn`和`stdio:'inherit'.它产生比`exec`和管道`stdout` /`stderr`更准确的输出,例如当从`git clone`显示进度信息时. (2认同)

Liv*_*ven 42

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

只需这样做:

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

spawn('coffee', ['-cw', 'my_file.coffee'], { stdio: 'inherit' });
Run Code Online (Sandbox Code Playgroud)

感谢@MorganTouvereyQuilling在本评论中指出这一点.

  • 为什么这不是公认的答案?这是唯一对我有用的,而且只有 2 f* 行!!! (3认同)

Kev*_*eur 21

我只想补充说,从生成的进程中输出缓冲区字符串的一个小问题console.log()是它添加了换行符,这可以将生成的进程输出扩展到其他行.如果你的输出stdoutstderrprocess.stdout.write()替代的console.log(),那么你会得到从衍生进程控制台输出"是".

我在这里看到了这个解决方案: Node.js:打印到控制台没有尾随换行符?

希望能帮助某人使用上面的解决方案(这对于实时输出来说非常棒,即使它来自文档).


Tyl*_*ong 17

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

var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);
Run Code Online (Sandbox Code Playgroud)

  • 这对于像“ls”这样的简单命令似乎工作得很好,但对于像“npm install”这样更复杂的命令却失败了。我什至尝试将 stdout 和 stderr 通过管道传输到各自的进程对象。 (2认同)

小智 9

我发现将自定义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())
  })
}
Run Code Online (Sandbox Code Playgroud)

app.js

const { exec } = require('./utilities.js')

exec('coffee -cw my_file.coffee')
Run Code Online (Sandbox Code Playgroud)


Ton*_*gfa 5

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

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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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