[英]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
});
在這種情況下,已經有一個execSync
函數:
child_process.execSync(命令[,options])
為了更通用的目的,現在您可以使用例如這個“生成器”模式來“解除”其中的任何異步函數 ,這對於任何順序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.