узел.js выполняет системную команду синхронно


мне нужно узел.js функции

result = execSync('node -v');

что будет одновременно выполните данную командную строку и верните все stdout'Ed по этому тексту команды.

ps. Синхронизация-это неправильно. Я знаю. Только для личного пользования.

обновление

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

обновление

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

обновление 2014-07-30

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


обновление 2015-02-10

НАКОНЕЦ-ТО! NodeJS 0.12 поддерживает execSync нативно.
Смотрите официальный docs

12 137

12 ответов:

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

child_process.execSync(command[, options])

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

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

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

посмотреть execSync библиотека.

Это довольно легко сделать с узел-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");

[EDIT Jun 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'));

использовать ShellJS модуль.

exec без предоставления обратного вызова.

пример:

var version = exec('node -v').output;

есть отличный модуль для управления потоком в узле.Яш называется 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...');
});

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

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

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

или, в если у вас есть слишком много времени, чтобы тратить, взломать вокруг в узле.js IT self.

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

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

пример:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);

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

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

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++, чтобы выполнить команды shell один за другим, выводя выходные данные команды на консоль в в реальном времени. Необязательно прикованный, и раскованных способов присутствуют; смысл что вы можете выбрать чтобы остановить скрипт, после того, как команда не (последовательно), или вы можете продолжать, как будто ничего не произошло !

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

EDIT:однако он еще не возвращает stdout... Просто выводит их в режиме реального времени.он делает сейчас. Ну, я только что выпустил его сегодня. Может быть, мы сможем построить на этом.

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

вы можете выполнять синхронные операции оболочки в 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\"));

EDIT-этот пример предназначен для сред windows, при необходимости отрегулируйте его для собственных нужд linux

на самом деле у меня была ситуация, когда мне нужно было запускать несколько команд одну за другой из пакета.сценарий предварительной установки 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']

EDIT: как уже отмечалось, это фактически не возвращает вывод или не позволяет использовать результат команд в Узловой программе. Один идея для этого-использовать обратные вызовы LiveScript. http://livescript.net/