node.js выполняет системную команду синхронно
Мне нужно в функции node.js
result = execSync('node -v');
это будет синхронно выполнять заданную командную строку и возвращать все stdout'ed по этому тексту команды.
пс. Синхронизация неверна. Я знаю. Просто для личного пользования.
ОБНОВИТЬ
Теперь у нас есть решение mgutz, которое дает нам код выхода, но не стандартный вывод! Все еще жду более точного ответа.
ОБНОВИТЬ
mgutz обновил свой ответ и решение здесь:)
Также, как упоминалось в dgo.a, есть отдельный модуль exec-sync
ОБНОВЛЕНИЕ 2014-07-30
ShellJS lib прибыла. Считайте, что это лучший выбор на данный момент.
ОБНОВЛЕНИЕ 2015-02-10
НАКОНЕЦ! NodeJS 0.12 поддерживает execSync
изначально.
Смотрите официальные документы
14 ответов
Node.js (начиная с версии 0.12 - так на некоторое время) поддерживает execSync
:
child_process.execSync(command[, options])
Теперь вы можете напрямую сделать это:
const execSync = require('child_process').execSync;
code = execSync('node -v');
и он будет делать то, что вы ожидаете. (По умолчанию направляет результаты ввода / вывода в родительский процесс). Обратите внимание, что вы также можете 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: Как получить 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'));
В файле 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...');
});
Собственное решение Node.js:
const {execSync} = require('child_process');
const result = execSync('node -v'); // this do the trick
Просто имейте в виду, что некоторые команды возвращаютBuffer
вместо того string
. В этом случае просто добавьтеencoding
к параметрам execSync:
const result = execSync('git rev-parse HEAD', {encoding: 'utf8'});
... и также хорошо иметь тайм-аут на синхронизацию exec:
const result = execSync('git rev-parse HEAD', {encoding: 'utf8', timeout: 10000});
Это невозможно в Node.js, оба child_process.spawn
а также 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
Это самый простой способ, который я нашел:
exec-Sync: https://github.com/jeremyfa/node-exec-sync
(Не путать с execSync.)
Выполнить команду оболочки синхронно. Используйте это для сценариев миграции, программ Cli, но не для обычного серверного кода.Пример:
var execSync = require('exec-sync');
var user = execSync('echo $USER');
console.log(user);
мой путь с 5 лет - иметь 2 строки;
const { execSync } = require('child_process');
const shell = (cmd) => execSync(cmd, {encoding: 'utf8'});
Тогда наслаждайтесь:
shell('git remote -v')
или
out = shell('ls -l')
.. скоро
Вы можете добиться этого, используя волокна. Например, используя мою библиотеку Common Node, код будет выглядеть так:
result = require('subprocess').command('node -v');
Я привыкла к реализации "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);
}
});
};
У меня была похожая проблема, и я закончил писать расширение узла для этого. Вы можете проверить репозиторий git. Это с открытым исходным кодом и бесплатно, и все такое хорошее!
https://github.com/aponxi/npm-execxi
ExecXI - это расширение узла, написанное на C++ для выполнения команд оболочки по очереди, выводящих вывод команды на консоль в режиме реального времени. Факультативно прикованы, и раскованные пути присутствуют; Это означает, что вы можете остановить сценарий после сбоя команды (цепочки) или продолжить, как будто ничего не произошло!
Инструкции по использованию находятся в файле ReadMe. Не стесняйтесь подавать заявки или отправлять вопросы!
РЕДАКТИРОВАТЬ: Однако он еще не возвращает стандартный вывод... Просто выводит их в режиме реального времени. Это сейчас. Ну, я только что выпустил это сегодня. Может быть, мы можем основываться на этом.
Во всяком случае, я думал, что стоит упомянуть об этом.
Вы можете выполнять синхронные операции оболочки в 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
У меня фактически была ситуация, когда мне нужно было запускать несколько команд одну за другой из сценария предварительной установки 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/