簡體   English   中英

node.js 同步執行系統命令

[英]node.js execute system command synchronously

我需要在node.js函數中

result = execSync('node -v');

這將同步執行給定的命令行並返回該命令文本的所有標准輸出。

附: 同步錯誤。 我知道。 僅供個人使用。

更新

現在我們有了 mgutz 的解決方案,它為我們提供了退出代碼,但沒有標准輸出! 仍在等待更准確的答案。

更新

mgutz更新了他的答案,解決方案在這里:)
另外,正如dgo.a提到的,有獨立模塊exec-sync

更新 2014-07-30

ShellJS庫到了。 考慮到這是目前最好的選擇。


更新 2015-02-10

最后! execSync 0.12 原生支持execSync
查看官方文檔

Node.js(從 0.12 版開始 - 所以有一段時間)支持execSync

child_process.execSync(command[, options])

您現在可以直接執行此操作:

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

它會做你所期望的。 (默認將 i/o 結果通過管道傳輸到父進程)。 請注意,您現在也可以spawnSync

請參閱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 月:如何獲得標准輸出]

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

使用ShellJS模塊。

exec函數而不提供回調。

示例:

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

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

這是我找到的最簡單的方法:

執行同步https : //github.com/jeremyfa/node-exec-sync
(不要與 execSync 混淆。)
同步執行shell命令。 將此用於遷移腳本、cli 程序,但不適用於常規服務器代碼。

示例:

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

這在 Node.js 中是不可能的, child_process.spawnchild_process.exec都是child_process.exec開始構建為異步的。

詳情見: https : //github.com/ry/node/blob/master/lib/child_process.js

如果你真的想要這個阻塞,那么把之后需要發生的所有事情都放在回調中,或者構建你自己的隊列以阻塞方式處理這個,我想你可以使用Async.js來完成這個任務。

或者,如果您有太多時間可以花,可以自己在 Node.js 中進行破解。

只是要補充一點,即使您應該使用它們的用例很少, spawnSync / execFileSync / execSync已在這些提交中添加到 node.js: https : //github.com/joyent/node/compare/d58c206862dc...e8df2676748e

原生 Node.js 解決方案是:

const {execSync} = require('child_process');

const result = execSync('node -v'); // 👈 this do the trick 

請注意,某些命令返回Buffer而不是string 如果您需要string只需將encoding添加到 execSync 選項:

const result = execSync('git rev-parse HEAD', {encoding: 'utf8'});

...並且同步執行超時也很好:

const result = execSync('git rev-parse HEAD', {encoding: 'utf8', timeout: 10000});

您可以使用纖維來實現這一點。 例如,使用我的公共節點庫,代碼如下所示:

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

我有一個類似的問題,我最終為此編寫了一個節點擴展。 您可以查看 git 存儲庫。 它是開源的,免費的,還有所有的好東西!

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

ExecXI是一個用C++編寫的節點擴展,用於逐條執行shell命令,將命令的輸出實時輸出到控制台。 存在可選的鏈式和非鏈式方式; 這意味着您可以選擇在命令失敗(鏈接)后停止腳本,或者您可以繼續,好像什么也沒發生!

使用說明在自述文件中 隨意提出請求請求或提交問題!

編輯: 但是它還沒有返回標准輸出......只是實時輸出它們。 現在確實如此。 嗯,我今天剛發布。 也許我們可以以此為基礎。

無論如何,我認為值得一提。

我習慣於在回調函數的末尾實現"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);
        }
    });
};

我實際上遇到過這樣的情況,我需要從 package.json 預安裝腳本中一個接一個地運行多個命令,這種方式可以在 Windows 和 Linux/OSX 上運行,所以我不能依賴非核心模塊。

所以這就是我想出的:

#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 程序中使用命令的結果。 另一個想法是使用 LiveScript 回撥。 http://livescript.net/

您可以像這樣在 nodejs 中執行同步 shell 操作:

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 需求進行調整

我 5 年來的方式是擁有 2 條線;

const { execSync } = require('child_process');
const shell = (cmd) => execSync(cmd, {encoding: 'utf8'});

然后享受: shell('git remote -v')out = shell('ls -l') .. 等等

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM