node.js выполняет системную команду синхронно - PullRequest
159 голосов
/ 14 декабря 2010

Мне нужно в node.js function

result = execSync('node -v');

, который синхронно выполнит заданную командную строку и вернет все stdout'ed по этому тексту команды.

пс. Синхронизация неверна. Я знаю. Просто для личного пользования.

UPDATE

Теперь у нас есть решение mgutz, которое дает нам код выхода, но не стандартный вывод! Все еще жду более точного ответа.

UPDATE

mgutz обновил свой ответ и решение здесь:)
Также, как упоминалось dgo.a , существует автономный модуль exec-sync

ОБНОВЛЕНИЕ 2014-07-30

ShellJS lib прибыла. Считайте, что это лучший выбор на данный момент.


ОБНОВЛЕНИЕ 2015-02-10

ПОСЛЕДНИМ! NodeJS 0.12 поддерживает execSync изначально.
См. Официальные документы

Ответы [ 12 ]

124 голосов
/ 08 февраля 2015

Node.js (начиная с версии 0.12 - так на время) поддерживает execSync:

child_process.execSync(command[, options])

Теперь вы можете напрямую сделать это:

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

и он будет делать то, что вы ожидаете. (По умолчанию направляет результаты ввода / вывода в родительский процесс). Обратите внимание, что вы также можете spawnSync сейчас.

54 голосов
/ 09 июня 2011

См. 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'));
31 голосов
/ 29 июля 2014

Использование ShellJS модуля.

exec функция без обеспечения обратного вызова.

Пример:

var version = exec('node -v').output;
23 голосов
/ 27 февраля 2012

В 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...');
});
11 голосов
/ 14 декабря 2010

Это невозможно в Node.js, и child_process.spawn, и child_process.exec были созданы с нуля, чтобы быть асинхронными.

Подробнее см .: https://github.com/ry/node/blob/master/lib/child_process.js

Если вы действительно хотите иметь эту блокировку, а затем поместить все, что должно произойти впоследствии, в обратный вызов, или создать свою собственную очередь для обработки этого блокирующим способом, я полагаю, вы можете использовать Async.js для этой задачи.

Или, если у вас слишком много времени, взломайте Node.js самостоятельно.

9 голосов
/ 15 сентября 2012

Это самый простой способ, который я нашел:

Exec-Sync : https://github.com/jeremyfa/node-exec-sync
(Не путать с execSync.)
Выполнить команду оболочки синхронно. Используйте это для скриптов миграции, программ cli, но не для обычного серверного кода.

Пример:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);
7 голосов
/ 12 мая 2014

Просто добавьте, что, хотя есть несколько вариантов использования, в которых вы должны их использовать, spawnSync / execFileSync / execSync были добавлены в node.js в этих коммитах: https://github.com/joyent/node/compare/d58c206862dc...e8df2676748e

5 голосов
/ 07 апреля 2012

Вы можете достичь этого, используя волокна. Например, при использовании моей библиотеки Common Node код будет выглядеть следующим образом:

result = require('subprocess').command('node -v');
3 голосов
/ 28 февраля 2013

У меня была похожая проблема, и я написал расширение узла для этого.Вы можете проверить репозиторий git.Это открытый исходный код, бесплатный и все такое хорошее!

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

ExecXI - расширение узла, написанное на C ++ для выполнения команд оболочки по одной, выводящих выходные данные команды вконсоль в режиме реального времени.Необязательные цепные и нецепные пути присутствуют;Это означает, что вы можете остановить сценарий после сбоя команды (цепочки) или продолжить, как будто ничего не произошло!

Инструкции по использованию содержатся в файле ReadMe .Не стесняйтесь отправлять запросы или отправлять вопросы!

РЕДАКТИРОВАТЬ: Однако это еще не возвращает стандартный вывод ... Просто выводит их в режиме реального времени. Так и есть. Ну, я только что выпустил его сегодня.Может быть, мы можем основываться на этом.

Во всяком случае, я думал, что стоит упомянуть об этом.

3 голосов
/ 24 декабря 2011

Я привыкла реализовывать "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);
        }
    });
};
...