node.jsはシステムコマンドを同期的に実行します


171

node.js関数に必要

result = execSync('node -v');

これは、指定されたコマンドラインを同期的に実行し、そのコマンドテキストで標準出力されたものをすべて返します。

ps。同期が間違っています。知っている。個人使用のみ。

更新

これで、終了コードを提供するが標準出力を提供しないmgutzのソリューションができました!より正確な答えを待っています。

更新

mgutzが彼の答えを更新し、解決策はここにあります:)
また、dgo.aが言及したように、スタンドアロンモジュールexec-syncがあります

アップデート2014-07-30

ShellJS libが到着しました。これが今のところ最良の選択だと考えてください。


更新2015-02-10

やっと!NodeJS 0.12はexecSyncネイティブでサポートしています。
公式ドキュメントを見る


26
だまされてはいけません、同期は間違っていません... NodeJSでも、明示的に非同期メソッドを呼び出さない限り、すべてのコードが同期的に実行されます... すべてが非同期で行われた場合、も行われません。また、非同期メソッドを優先しても、長時間の計算によってサーバーがブロックされないわけではありません。それは選択です。Nodeのメーカーが非同期のファイルシステムメソッドと同期のファイルシステムメソッドを提供することを選択したのは、それらの場所もあることを示すためです。
フロー

2
あなたが話している「Unixシェルエミュレーションライブラリ」はどこにありますか?
フロリアン

@Florian彼は意味ShellJS
XST

回答:


153

Node.js(バージョン0.12以降-しばらくの間)は以下をサポートしますexecSync

child_process.execSync(command[, options])

これで直接これを行うことができます:

const execSync = require('child_process').execSync;
code = execSync('node -v');

そしてそれはあなたが期待することをします。(デフォルトでは、I / O結果を親プロセスにパイプします)。spawnSync今もできることに注意してください。


6
絶望の10時間後。THANKS DUDE
Tom Dev

このサブプロセスから切断するにはどうすればよいですか?
JulianSoto


54

execSyncライブラリを参照してください。

node-ffiを使用するのはかなり簡単です。私はサーバープロセスにはお勧めしませんが、一般的な開発ユーティリティでは、物事を成し遂げます。ライブラリをインストールします。

npm install node-ffi

スクリプトの例:

var FFI = require("node-ffi");
var libc = new FFI.Library(null, {
  "system": ["int32", ["string"]]
});

var run = libc.system;
run("echo $USER");

[2012年6月編集:STDOUTの入手方法]

var lib = ffi.Library(null, {
    // FILE* popen(char* cmd, char* mode);
    popen: ['pointer', ['string', 'string']],

    // void pclose(FILE* fp);
    pclose: ['void', [ 'pointer']],

    // char* fgets(char* buff, int buff, in)
    fgets: ['string', ['string', 'int','pointer']]
});

function execSync(cmd) {
  var
    buffer = new Buffer(1024),
    result = "",
    fp = lib.popen(cmd, 'r');

  if (!fp) throw new Error('execSync error: '+cmd);

  while(lib.fgets(buffer, 1024, fp)) {
    result += buffer.readCString();
  };
  lib.pclose(fp);

  return result;
}

console.log(execSync('echo $HOME'));

2
これから何を実際に送信するのstdoutですか?私が得ることができるのは、プロセス終了コード
Mark Kahn、

@cwolves:非同期のほうがいいと思います。(Ivoの回答
pvorb

@pvorb-ええ、非同期を使用できない場合を除きます:)
Mark Kahn

1
すべての爪に非同期ハンマーを使用しないことには正当な理由があります。たとえば、テンプレートエンジンはExpress 3では非同期であり、ヘルパー関数(ローカル)は同期する必要があります。これらのヘルパー関数がLessファイルをその場で非同期にコンパイルする必要がある場合はどうなりますか?
mgutz 2012年

8
なぜこのシンプルexecSyncはの一部ではないのでしょうかchild_process。そうだと思います。
MichaelHärtl2012

31

ShellJSモジュールを使用します。

コールバックを提供しないexec関数。

例:

var version = exec('node -v').output;

2
これを書いている時点で、ドキュメントは同期exec()が長いプロセスに対してCPUを集中的に使用することを述べていることに注意してください。
Aram Kocharyan 2014

1
オプション、{silent:true}がキー
Nick

1
これは何かをします(短い構文を提供する以外に)これはしませんか?const execSync = require('child_process').execSync; code = execSync('node -v');
user2503764 2017

23

node.jsには、asyncblockというフロー制御用の優れたモジュールがあります。関数でコードをラップしても問題ない場合は、次のサンプルを検討してください。

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

asyncblock(function (flow) {
    exec('node -v', flow.add());
    result = flow.wait();
    console.log(result);    // There'll be trailing \n in the output

    // Some other jobs
    console.log('More results like if it were sync...');
});

1
彼は、制御フローライブラリではなく、同期バージョンについて明示的に尋ねました。
Alexey Petrushin 2013年

22
@AlexeyPetrushinここでのすべての質問は目標に関するものであり、それを達成するための特定の方法に関するものではありません。でも投票してくれてありがとう。
nab

1
また、これはWindowsユーザーにとって非常に役立つ回答です。Windowsへのインストールexec-syncffiオーバーヘッドは非常に大きくなります(VC ++、SDK、Pythonなど)が、これは軽量です。
Mendhak

10

これは、Node.jsのでは不可能で、両方child_process.spawnchild_process.exec非同期であることを基礎から構築されました。

詳細については、https//github.com/ry/node/blob/master/lib/child_process.jsを参照してください。

このブロッキングが本当に必要な場合は、後で発生する必要があるすべてをコールバックに入れるか、独自のキューを作成してこれをブロッキング方式で処理する場合、このタスクにAsync.jsを使用できると思います。

または、時間をかけすぎる場合は、Node.jsを自分でハックしてください。


12
ファイルシステムモジュールに同期呼び出しがあるため、奇妙です。なぜ実行しないのですか?
アルフレッド、

4
@Alfred同期FS呼び出しは主に、プログラムの開始時に構成をロードするためのものです。
Ivo Wetzel 2010

3
@IvoWetzel-tisk tisk ...何かが不可能だと決して言わないことを学んだのではないですか?;)以下の私のソリューションを参照してください。
マーカスポープ

1
@IvoWetzel "同期FS呼び出し..."-そうです。たとえば、プログラムの開始時に何かをコンパイルし、完了時に続行するコマンドを発行したい場合があります。—同期execがない同期FS呼び出しがある場合見落としのように見えます。私はすべて非同期ですが、同期には長所と使用例があります。もちろん、賢明な方法で使用する必要があります。
フロー

非同期は問題ありませんが、WidgetBがWidgetAの最終結果に依存している場合、世界中のすべての非同期は仕事を完了しません。時々、プロセスは同期的でなければなりません。非同期で調理してみてください。;)
ロイドサージェント

9

これは私が見つけた最も簡単な方法です:

exec-Synchttps : //github.com/jeremyfa/node-exec-sync
(execSyncと混同しないでください。)
シェルコマンドを同期的に実行します。これは移行スクリプト、cliプログラムに使用しますが、通常のサーバーコードには使用しません。

例:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);


5

繊維を使用してこれを実現できます。たとえば、私のCommon Nodeライブラリを使用すると、コードは次のようになります。

result = require('subprocess').command('node -v');

3

"synchronous"コールバック関数の最後に何かを実装することに慣れています。あまり良くありませんが、うまくいきます。コマンドライン実行のシーケンスを実装する必要がある場合はexec、名前付き関数にラップして再帰的に呼び出す必要があります。このパターンは私には使いやすいようです:

SeqOfExec(someParam);

function SeqOfExec(somepParam) {
    // some stuff
    // .....
    // .....

    var execStr = "yourExecString";
    child_proc.exec(execStr, function (error, stdout, stderr) {
        if (error != null) {
            if (stdout) {
                throw Error("Smth goes wrong" + error);
            } else {
                // consider that empty stdout causes
                // creation of error object
            }
        }
        // some stuff
        // .....
        // .....

        // you also need some flag which will signal that you 
        // need to end loop
        if (someFlag ) {
            // your synch stuff after all execs
            // here
            // .....
        } else {
            SeqOfExec(someAnotherParam);
        }
    });
};

3

私は同様の問題を抱えていて、結局このためのノード拡張を作成しました。gitリポジトリをチェックアウトできます。それはオープンソースであり、無料であり、すべてが良いものです!

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

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

使用方法はReadMeファイルにあります。プルリクエストや問題の送信はお気軽に!

編集: ただし、標準出力はまだ返されません...リアルタイムで出力するだけです。 今はそうです。さて、今日リリースしました。たぶん、その上に構築できるでしょう。

とにかく、それは言及する価値があると思いました。


これはまさに私が探していたものです。これを作る時間を割いていただきありがとうございます。
thealfreds 2013

私が理解して実装していない唯一のことは、異なるnodejsバージョンのビルド構成です。私はそれをノード0.8(travis-ci.org/aponxi/npm-execxi/builds/5248535)で書いたので、npm install成功する限り(つまり、プラグインのコンパイル時に)、本番環境に移行することをお勧めします。異なるnodejsバージョンを対象とすることに加えて、本番用にパッチが適用されているか、かなり安定しています。バグがある場合は、プルリクエストで送信するか、githubに問題を投稿してください:)
Logan

1

次のようにnodejsで同期シェル操作を行うことができます:

var execSync = function(cmd) {

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

    //for linux use ; instead of &&
    //execute your command followed by a simple echo 
    //to file to indicate process is finished
    exec(cmd + " > c:\\stdout.txt && echo done > c:\\sync.txt");

    while (true) {
        //consider a timeout option to prevent infinite loop
        //NOTE: this will max out your cpu too!
        try {
            var status = fs.readFileSync('c:\\sync.txt', 'utf8');

            if (status.trim() == "done") {
                var res = fs.readFileSync("c:\\stdout.txt", 'utf8');
                fs.unlinkSync("c:\\stdout.txt"); //cleanup temp files
                fs.unlinkSync("c:\\sync.txt");
                return res;
            }
        } catch(e) { } //readFileSync will fail until file exists
    }

};

//won't return anything, but will take 10 seconds to run
console.log(execSync("sleep 10")); 

//assuming there are a lot of files and subdirectories, 
//this too may take a while, use your own applicable file path
console.log(execSync("dir /s c:\\usr\\docs\\"));

編集-この例は、Windows環境用です。必要に応じて、独自のLinuxニーズに合わせて調整してください


はい、そしてあなたのCPUが召喚できるのと同じくらい速く...しかし、あなたが何か悪いことをする必要があるとき、ねえ、サタンはあなたの権利ですよね?
マーカス・ポープ

わかりました、これは純粋な悪ですが、素晴らしいです。これは、コールバックのないファイルシステムイベントbrowserify.on( 'register')を処理するために必要でした。私の日を救った!
Robert Gould

これがJavaScriptエンジンで機能する理由を説明できますか?execが次のティックで実行されている間に、whileループが同じティックで無限に実行されるべきではありませんか?
badunk

忙しい待機によってCPUを最大限に活用することは悪い設計です。
ルイ

@ Louis-DominiqueDubeauもちろん、クロスプラットフォーム互換であるかどうかにかかわらず、サードパーティのソースに依存しない代替手段は実際にはありません。OSはnodejsプロセスに完全な優先順位を与えないため、これはCPUの真の最大化ではありません。シェル操作の同期の実装は地平線上にあるか、おそらくすでにここにあると思います。
マーカスポープ

1

実際に、WindowsとLinux / OSXの両方で機能するように、package.jsonプレインストールスクリプトから複数のコマンドを次々と実行する必要があり、非コアモジュールに依存できない状況がありました。

これが私が思いついたものです:

#cmds.coffee
childproc = require 'child_process'

exports.exec = (cmds) ->
  next = ->
    if cmds.length > 0
      cmd = cmds.shift()
      console.log "Running command: #{cmd}"
      childproc.exec cmd, (err, stdout, stderr) ->
        if err? then console.log err
        if stdout? then console.log stdout
        if stderr? then console.log stderr
        next()
    else
      console.log "Done executing commands."

  console.log "Running the follows commands:"
  console.log cmds
  next()

次のように使用できます。

require('./cmds').exec ['grunt coffee', 'nodeunit test/tls-config.js']

編集:指摘したように、これは実際には出力を返さず、Nodeプログラムでコマンドの結果を使用することもできません。そのためのもう1つのアイデアは、LiveScriptバックコールを使用することです。 http://livescript.net/


おかげで、これはあなたのコード以来の答えではありませんが、一連のコマンドを実行し、非同期
disfated

私の例のように一連のコマンドを同期的に実行する必要がある場合、それは機能します。申し訳ありませんが、あなたの質問を誤解したと思います。答えに別のアイデアを追加しました。
Jason Livesay 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.