Exec:stdoutの「ライブ」を表示


188

私はこの簡単なスクリプトを持っています:

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

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

ここでは、コーヒースクリプトファイルをコンパイルするコマンドを実行するだけです。ただし、コマンドが終了しないため(コーヒーの-wオプションのため)、stdoutはコンソールに表示されません。コンソールから直接コマンドを実行すると、次のようなメッセージが表示されます。

18:05:59 - compiled my_file.coffee

私の質問は:node.js execでこれらのメッセージを表示することは可能ですか?はいの場合はどうですか?!

ありがとう


1
Python実行可能ファイルからstdoutをキャプチャするためにここに来ました。以下のすべてが機能しますが、「-u」オプションを使用してpythonを実行し、outoutをバッファリングせずにライブ更新する必要があることに注意してください。
アンディ

回答:


266

使用しないでください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());
});

exec 出力をバッファリングし、通常、コマンドの実行が終了するとそれを返します。


22
非常に素晴らしい。FYI:標準出力/標準エラーイベントは、引数のデータを"コールバックので)(.toStringでそれを呼び出すバッファである
セルゲル

4
Windowsでスポーンすることができない人のために、この素​​晴らしい答えを見てください。
tomekwi 2014

17
execも少なくとも最新ではEventEmitterです。
Nikolay Tsenkov 2015年

4
また、プログラムが改行を出力するときには、コールバックは呼び出されないことにも注意してください。子プロセスから「イベント」を受信する場合flush(stdout);、Node.jsでイベントを発生させるために、このプロセスはバッファー(C)をフラッシュする必要があります。
ジュリアンF.ウェイナート2016年

5
execの+1はEventEmitterでもあります。文字列をargs配列にリファクタリングするのに2時間を費やしました(非常に長くて複雑なffmpegコマンドライン)。
デッドカンバセーション2016

176

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、子プロセスのstdoutからメインstdoutへ。

coffeeProcess.stdout.pipe(process.stdout);

または、spawnを使用してstdioを継承します

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

35
このように見えるだけで使用することによって単純化することができるpipecoffeeProcess.stdout.pipe(process.stdout);
エリックFreeseの

3
@EricFreeseのコメントは、stdoutの文字置換機能(ノードスクリプトの分度器を利用)を活用したかったため、私が探していたものです
LoremIpsum

19
シンプル:spawn(cmd, argv, { stdio: 'inherit' })。さまざまな例については、nodejs.org / api / child_process.html#child_process_options_stdioをご覧ください。
Morgan Touverey Quilling 2017

3
使用するMorganTouvereyQuillingの提案@のための+1 spawnstdio: 'inherit'。たとえばからの進行状況情報を表示する場合、execパイプラインstdout/ よりも正確な出力を生成します。stderrgit clone
Livven

58

すでにいくつかの回答がありますが、どれもこれを使用する最適な(そして最も簡単な)方法について言及しておらず、spawn{ stdio: 'inherit' }オプションを使用しています。たとえばからの進捗情報を表示する場合など、最も正確な出力が生成されるようgit cloneです。

単にこれを行う:

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

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

このコメントこれを指摘した@MorganTouvereyQuillingの功績によるものです。


1
サブプロセスがカラーテキストのようなフォーマットされた出力を使用する場合、stdio: "inherit"そのフォーマットは保持しますが、保持しchild.stdout.pipe(process.stdout)ません。
リッキギブソン

これにより、npmインストールの進行状況バーのような複雑な出力のプロセスでも出力が完全に保持されます。驚くばかり!
Dave Koo

1
なぜこれは受け入れられない答えですか?それは私のために働いた唯一のものであり、それはちょうど2つのf *ラインです!!!
リンカーン

このヒントは、プログレスバーを使用するSymfonyコマンドラインアプリケーションを実行するときに役立ちました。乾杯。
ハーフストップ

これは完璧な出力表現を維持する受け入れ答え、唯一のものでなければなりませんし、それが最も簡単なの?はいください
evnp

21

生成されたプロセスからバッファ文字列を出力する際の小さな問題の1つにconsole.log()、改行が追加されることを追加します。これにより、生成されたプロセスの出力を追加の行に分散できます。あなたの出力した場合stdoutまたはstderrprocess.stdout.write()代わりのconsole.log()、そしてあなたは「そのまま」生成されたプロセスからのコンソール出力を取得します。

私はここでそのソリューションを見ました: Node.js:末尾の改行なしでコンソールに出力しますか?

上記のソリューションを使用している人に役立つことを願っています(ドキュメントからであっても、ライブ出力には最適です)。


1
spawn(command, args, { stdio: 'inherit' })@MorganTouvereyQuillingによって提案されているように、より正確な出力を使用するには、stackoverflow.com
questions / 10232192 /…

21

ナタナエル・スミスの答えとエリック・フリーズのコメントに触発されて、それは次のように簡単かもしれません:

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

これは、などの単純なコマンドでは正常にls機能するようですが、などのより複雑なコマンドでは失敗しますnpm install。stdoutとstderrの両方をそれぞれのプロセスオブジェクトにパイプ接続してみました。
linuxdan

@linuxdan npmがstderrで書き込んでいることが原因である可能性があります(そこにプログレスバーを書き込む人がいるのを見ました)。stderrをパイプするか、Tongfaソリューションを拡張してstderrでリッスンすることもできます。
セルジュ2017年

@linuxdan私が見た中で最も信頼できる方法はspawn(command, args, { stdio: 'inherit' })、ここで提案されているように、stackoverflow.com
questions / 10232192 /…

ベストアンサー、ありがとうございます。魅力のように働きました
Abhishek Sharma

12

これを行うユーティリティにカスタム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')

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);
    });
}

場合dataによっては複数行になるため、oldSchoolMakeBuildヘッダーは複数行に1回表示されます。しかし、これはそれを変更するのに十分気になりませんでした。


3

child_process.spawnは、stdoutおよびstderrストリームを持つオブジェクトを返します。stdoutストリームをタップして、子プロセスがノードに送り返すデータを読み取ることができます。ストリームであるstdoutには、「データ」、「終了」、およびストリームが持つ他のイベントがあります。spawnは、子プロセスが大量のデータをノードに返すようにする場合に最適です-画像処理、バイナリデータの読み取りなど。

したがって、以下で使用する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());
});

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})
        })
    })
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.