116

Linux または Windows シェル コマンドを実行し、node.js 内で出力をキャプチャする方法の詳細をまだ把握しようとしています。最終的にはこんなことをしたい…

//pseudocode
output = run_command(cmd, args)

重要な部分はoutput、グローバル スコープの変数 (またはオブジェクト) で使用できる必要があることです。次の機能を試しましたが、何らかの理由でundefinedコンソールに出力されます...

function run_cmd(cmd, args, cb) {
  var spawn = require('child_process').spawn
  var child = spawn(cmd, args);
  var me = this;
  child.stdout.on('data', function(me, data) {
    cb(me, data);
  });
}
foo = new run_cmd('dir', ['/B'], function (me, data){me.stdout=data;});
console.log(foo.stdout);  // yields "undefined" <------

上記のコードが壊れている場所を理解するのに苦労しています...そのモデルの非常に単純なプロトタイプが機能します...

function try_this(cmd, cb) {
  var me = this;
  cb(me, cmd)
}
bar = new try_this('guacamole', function (me, cmd){me.output=cmd;})
console.log(bar.output); // yields "guacamole" <----

なぜtry_this()機能し、run_cmd()機能しないのかを誰かが理解するのを手伝ってくれますか? FWIW、200KBのバッファ制限があるchild_process.spawnため、使用する必要があります。child_process.exec

最終決議

私はジェームズ・ホワイトの答えを受け入れていますが、これは私のために働いた正確なコードです...

function cmd_exec(cmd, args, cb_stdout, cb_end) {
  var spawn = require('child_process').spawn,
    child = spawn(cmd, args),
    me = this;
  me.exit = 0;  // Send a cb to set 1 when cmd exits
  me.stdout = "";
  child.stdout.on('data', function (data) { cb_stdout(me, data) });
  child.stdout.on('end', function () { cb_end(me) });
}
foo = new cmd_exec('netstat', ['-rn'], 
  function (me, data) {me.stdout += data.toString();},
  function (me) {me.exit = 1;}
);
function log_console() {
  console.log(foo.stdout);
}
setTimeout(
  // wait 0.25 seconds and print the output
  log_console,
250);
4

10 に答える 10

90

ここには、修正する必要がある 3 つの問題があります。

1つ目は、stdout を非同期で使用しているときに同期動作が期待されていることです。関数内のすべての呼び出しrun_cmdは非同期であるため、データの一部または全部が stdout から読み取られたかどうかに関係なく、子プロセスが生成されてすぐに返されます。そのため、実行すると

console.log(foo.stdout);

現時点で foo.stdout に保存されているものは何でも取得しますが、子プロセスがまだ実行されている可能性があるため、それがどうなるかは保証されません。

2 つ目は、stdout が読み取り可能なストリームであるため、1) データ イベントを複数回呼び出すことができ、2) コールバックには文字列ではなくバッファーが与えられることです。簡単に修復できます。ただ変える

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, data){me.stdout=data;}
);

の中へ

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, buffer){me.stdout+=buffer.toString();}
);

バッファを文字列に変換し、その文字列を stdout 変数に追加します。

3つ目は、「終了」イベントを取得したときにのみ、すべての出力を受信したことを知ることができるということです。つまり、別のリスナーとコールバックが必要です。

function run_cmd(cmd, args, cb, end) {
    // ...
    child.stdout.on('end', end);
}

したがって、最終結果は次のとおりです。

function run_cmd(cmd, args, cb, end) {
    var spawn = require('child_process').spawn,
        child = spawn(cmd, args),
        me = this;
    child.stdout.on('data', function (buffer) { cb(me, buffer) });
    child.stdout.on('end', end);
}

// Run C:\Windows\System32\netstat.exe -an
var foo = new run_cmd(
    'netstat.exe', ['-an'],
    function (me, buffer) { me.stdout += buffer.toString() },
    function () { console.log(foo.stdout) }
);
于 2013-01-24T21:06:59.487 に答える
79

受け入れられた回答(3番目のポイント)の簡略版は、私にとってはうまくいきました。

function run_cmd(cmd, args, callBack ) {
    var spawn = require('child_process').spawn;
    var child = spawn(cmd, args);
    var resp = "";

    child.stdout.on('data', function (buffer) { resp += buffer.toString() });
    child.stdout.on('end', function() { callBack (resp) });
} // ()

使用法:

run_cmd( "ls", ["-l"], function(text) { console.log (text) });

run_cmd( "hostname", [], function(text) { console.log (text) });
于 2013-07-04T09:16:29.287 に答える
52

私はこれをより簡潔に使用しました:

var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", puts);

それは完全に機能します。:)

于 2014-04-18T14:40:29.410 に答える
45

最も簡単な方法は、ShellJS ライブラリを使用することです ...

$ npm install [-g] shelljs

EXEC 例:

require('shelljs/global');

// Sync call to exec()
var version = exec('node --version', {silent:true}).output;

// Async call to exec()
exec('netstat.exe -an', function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});

ShellJs.orgは、次のような NodeJS 関数としてマップされた多くの一般的なシェル コマンドをサポートしています。

  • CD
  • chmod
  • CP
  • ディレクトリ
  • エコー
  • エグゼクティブ
  • 出口
  • 探す
  • grep
  • ls
  • mkdir
  • mv
  • ポップド
  • 押した
  • pwd
  • RM
  • シード
  • テスト
  • どれの
于 2014-07-16T09:28:01.467 に答える
4

同様の問題があり、最終的にこのためのノード拡張を作成しました。git リポジトリをチェックアウトできます。それはオープン ソースであり、無料であり、すべてが優れています。

https://github.com/aponxi/npm-execxi

ExecXI は、C++ で記述されたノード拡張機能で、シェル コマンドを 1 つずつ実行し、コマンドの出力をリアルタイムでコンソールに出力します。オプションの連鎖および非連鎖ウェイが存在します。つまり、コマンドが失敗した後 (連鎖) にスクリプトを停止することも、何も起こらなかったかのように続行することもできます。

使用方法はReadMe ファイルに記載されています。気軽にプル リクエストを作成したり、Issue を送信したりしてください。

言及する価値があると思いました。

于 2013-02-28T07:31:06.183 に答える
4

@TonyO'Hagan は包括的なshelljs回答ですが、彼の回答の同期バージョンを強調したいと思います。

var shell = require('shelljs');
var output = shell.exec('netstat -rn', {silent:true}).output;
console.log(output);
于 2016-09-23T00:41:02.883 に答える
0

関数に変数の競合がありますrun_cmd

  var me = this;
  child.stdout.on('data', function(me, data) {
    // me is overriden by function argument
    cb(me, data);
  });

これに変更するだけです:

  var me = this;
  child.stdout.on('data', function(data) {
    // One argument only!
    cb(me, data);
  });

エラーを確認するには、常に次を追加してください。

  child.stderr.on('data', function(data) {
      console.log( data );
  });

編集別のスタンドアロンプ​​ログラムとして提供されてdirない実行しようとしているため、コードが失敗します。処理中のコマンドcmdです。ファイルシステムで遊びたい場合は、nativeを使用してくださいrequire( 'fs' )

または(お勧めしません)、バッチファイルを作成して実行することもできます。OSはデフォルトで、を介してバッチファイルを起動することに注意してくださいcmd

于 2013-01-22T13:03:45.443 に答える
0

run_cmd 関数から実際には何も返していません。

function run_cmd(cmd, args, done) {
    var spawn = require("child_process").spawn;
    var child = spawn(cmd, args);
    var result = { stdout: "" };
    child.stdout.on("data", function (data) {
            result.stdout += data;
    });
    child.stdout.on("end", function () {
            done();
    });
    return result;
}

> foo = run_cmd("ls", ["-al"], function () { console.log("done!"); });
{ stdout: '' }
done!
> foo.stdout
'total 28520...'

うまく動作します。:)

于 2013-01-25T03:11:37.470 に答える
0

最も受賞歴のある回答の約束されたバージョン:

  runCmd: (cmd, args) => {
    return new Promise((resolve, reject) => {
      var spawn = require('child_process').spawn
      var child = spawn(cmd, args)
      var resp = ''
      child.stdout.on('data', function (buffer) { resp += buffer.toString() })
      child.stdout.on('end', function () { resolve(resp) })
    })
  }

使用するには:

 runCmd('ls').then(ret => console.log(ret))
于 2018-02-10T06:17:59.390 に答える