2010-12-14 3 views
126

мне нужно в node.js функцииnode.js выполнить системную команду синхронно

result = execSync('node -v'); 

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

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

UPDATE

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

UPDATE

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

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

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


UPDATE 2015-02-10

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

+16

не позволяйте себе обманываться, синхронизация не является ошибкой ... ДАЖЕ в NodeJS весь ваш код выполняется синхронно, если вы явно не вызвали метод асинхронного программирования ... если * все * было сделано асинхронным способом * ничего * никогда не будет сделано. также, предпочитая асинхронные методы, не означает, что ваш длительный расчет не будет блокировать ваш сервер. это выбор. что создатели Node решили предоставить синхронные методы файловой системы наряду с асинхронными, просто показывают, что для них тоже есть место. – flow

+2

Где мы можем найти «библиотеку эмуляции оболочки Unix», о которой вы говорите? – Florian

+0

@Florian означает [ShellJS] (https://github.com/arturadib/shelljs) – xst

ответ

86

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

child_process.execSync(command[, options]) 

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

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

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

+1

после 10 часов отчаяния. СПАСИБО ПРИЯТЕЛЬ –

11

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

Для получения дополнительной информации см: https://github.com/ry/node/blob/master/lib/child_process.js

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

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

+12

странно, потому что модуль файловой системы имеет синхронные вызовы. Почему бы и не выполнить? – Alfred

+4

@Alfred Синхронизация вызовов FS в основном используется для загрузки конфигураций при запуске программы. –

+1

@IvoWetzel - tisk tisk ... разве мы не научились никогда не говорить, что что-то невозможно? ;) см. мое решение ниже. –

54

См. execSync library.

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

[EDIT июня 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')); 
+2

Как вы могли бы на самом деле получить что-нибудь, отправленное на 'stdout'? Все, что я могу получить, это код выхода процесса –

+0

@cwolves: Я думаю, что асинк будет лучше. ([Иво ответ] (http://stackoverflow.com/a/4443678/432354)) – pvorb

+0

@pvorb - да, если вы не можете использовать async :) –

3

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

вы можете сделать синхронные операции оболочки в 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 - этот пример предназначен для окон среды, настроить для своего собственного Linux при необходимости необходимо

+17

Этот мир кода также призван призвать сатану? :) – disfated

+0

Да, и так быстро, как ваш процессор может вызвать ... Но эй, когда тебе «нужно» сделать что-то злобное, сатана ваш твой прав? –

+0

хорошо, это чистое зло, но удивительно. Мне это нужно для обработки события файловой системы browserify.on ('register'), у которого не было обратного вызова. Спас мой день! –

20

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

Он прямо спросил о версии синхронизации, а не о контрольных библиотеках потоков. –

+20

@AlexeyPetrushin Каждый вопрос здесь о цели, а не о конкретном способе ее достижения. Спасибо за downvoting, хотя. – nab

+1

Кроме того, это очень полезный ответ для пользователей Windows; установка 'exec-sync' или' ffi' в Windows имеет огромные накладные расходы (VC++, SDK, Python и т. д.), но это легче. – Mendhak

5

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

result = require('subprocess').command('node -v'); 
9

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

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

Пример:

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

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

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

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

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

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

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

+0

Это именно то, что я искал. Спасибо, что постарались сделать это. – thealfreds

+0

Эта вещь хорошо выглядит ... может ли она использоваться при приведении? –

+0

Единственное, что я не понял и не реализовал, это конфигурация сборки для разных версий nodejs. Наверное, я написал его на узле 0.8 (https://travis-ci.org/aponxi/npm-execxi/builds/5248535), так как до тех пор, пока 'npm install' удастся (другими словами, как компиляторы плагинов), тогда это хорошо идти на производство. Помимо таргетинга на различные версии nodejs, я бы сказал, что он исправлен для производства или что он довольно стабилен. Если есть ошибки, вы можете отправить запрос на перенос или опубликовать сообщение об ошибке в github :) – Logan

1

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

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

+0

Спасибо, но это не ответ, так как ваш код запускает команды последовательно ** асинхронно ** – disfated

+0

Если вам нужно выполнить серию команды синхронно, как в моем примере, он будет работать. Кажется, я неправильно понял ваш вопрос, извините. Я добавил еще одну идею к ответу. –

7

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

+0

Означает ли это, что мы будем иметь его в v0.12 из коробки? – disfated

+0

@ disfated yes: http: // strongloop.com/strongblog/whats-new-in-node-js-v0-12-execsync-a-synchronous-api-for-child-процессы/ – balupton

31

Используйте ShellJS модуль.

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

Пример:

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

Обратите внимание, что на момент написания документа в документах упоминается, что синхронный 'exec () 'интенсивность процессора для длинных процессов. –

+0

опции, {silent: true} является ключом – Nick

+0

Это что-то (кроме синтаксиса более короткого), это не так? 'const execSync = require ('child_process'). execSync; code = execSync ('node -v'); ' – user2503764

Смежные вопросы