簡體   English   中英

如何按順序執行shell命令?

[英]How can I execute shell commands in sequence?

我有一個我想用nodejs執行的shell命令列表:

// index.js
var commands = ["npm install", "echo 'hello'"];

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

for (var i = 0; i < commands.length; i++) {
    exec(commands[i], function(err, stdout) {
        console.log(stdout);
    });
}

當我運行它時,命令以相反的順序執行。 為什么會這樣? 我如何按順序執行命令?

更好的是,有沒有辦法在不使用nodejs的情況下執行shell命令? 我發現它對shell的異步處理有點麻煩。

注意:

我知道像shelljs這樣的shelljs在。 我正在嘗試僅使用基本nodejs。

你的for循環正在同時並行執行所有異步操作,因為exec()是非阻塞的。 他們將完成的順序取決於他們的執行時間,並且不會確定。 如果你真的希望它們被排序,那么你必須執行一個,等待它調用它的完成回調,然后執行下一個。

您不能使用傳統的for循環來“等待”異步操作以在Javascript中完成以便按順序執行它們。 相反,您必須手動進行迭代,然后在前一個完成回調中啟動下一次迭代。 我通常的做法是使用一個計數器和一個名為next()的本地函數,如下所示:

手動異步迭代

var commands = ["npm install", "echo 'hello'"];

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

function runCommands(array, callback) {

    var index = 0;
    var results = [];

    function next() {
       if (index < array.length) {
           exec(array[index++], function(err, stdout) {
               if (err) return callback(err);
               // do the next iteration
               results.push(stdout);
               next();
           });
       } else {
           // all done here
           callback(null, results);
       }
    }
    // start the first iteration
    next();
}

runCommands(commands, function(err, results) {
    // error or results here
});

ES6承諾

由於promises已在ES6中標准化並且現在已內置到node.js中,因此我喜歡使用Promises進行異步操作:

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

function execPromise = function(cmd) {
    return new Promise(function(resolve, reject) {
        exec(cmd, function(err, stdout) {
            if (err) return reject(err);
            resolve(stdout);
        });
    });
}

var commands = ["npm install", "echo 'hello'"];

commands.reduce(function(p, cmd) {
    return p.then(function(results) {
        return execPromise(cmd).then(function(stdout) {
            results.push(stdout);
            return results;
        });
    });
}, Promise.resolve([])).then(function(results) {
    // all done here, all results in the results array
}, function(err) {
    // error here
});

藍鳥承諾

使用Bluebird promise庫,這將更簡單:

var Promise = require('bluebird');
var execP = Promise.promisify(require('child_process').exec);

var commands = ["npm install", "echo 'hello'"];
Promise.mapSeries(commands, execP).then(function(results) {
    // all results here
}, function(err) {
    // error here
});

選項1:使用函數的“...同步”版本(如果存在)

在這種情況下,已經有一個execSync函數:

child_process.execSync(命令[,options])

選項2:發電機魔術!

為了更通用的目的,現在您可以使用例如這個“生成器”模式來“解除”其中的任何異步函數 ,這對於任何順序OS腳本都非常有用。

這里有一個如何在node.js v6 +中以同步方式使用readline異步函數的例子(我想也是v4 +)

var main = (function* () {
  var rl = require('readline')
          .createInterface({input: process.stdin, output: process.stdout });
  // the callback uses the iterator '.next()' to resume the 'yield'
  a = yield rl.question('do you want this? ', r=>main.next(r))  
  b = yield rl.question('are you sure? ', r=>main.next(r))      
  rl.close()
  console.log(a,b)
})()          // <- generator executed, iterator 'main' created
main.next()   // <- start iterator, run till the first 'yield'

暫無
暫無

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

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