如何按顺序执行shell命令?

dop*_*man 3 shell node.js

我有一个我想用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);
    });
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,命令以相反的顺序执行.为什么会这样?我如何按顺序执行命令?

更好的是,有没有办法在不使用nodejs的情况下执行shell命令?我发现它对shell的异步处理有点麻烦.

注意:

我知道图书馆就像shelljs存在一样.我正在尝试仅使用基本nodejs.

jfr*_*d00 8

您的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
});
Run Code Online (Sandbox Code Playgroud)

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
});
Run Code Online (Sandbox Code Playgroud)

蓝鸟承诺

使用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
});
Run Code Online (Sandbox Code Playgroud)