node.js executa o comando do sistema de forma síncrona

Eu preciso da function node.js

result = execSync('node -v'); 

que irá executar de forma síncrona a linha de comando dada e retornar todos os stdout’ed por esse texto de comando.

ps. A synchronization está errada. Eu sei. Apenas para uso pessoal.

ATUALIZAR

Agora temos a solução de mgutz que nos dá o código de saída, mas não stdout! Ainda esperando por uma resposta mais precisa.

ATUALIZAR

mgutz atualizou sua resposta e a solução está aqui 🙂
Além disso, como dgo.a mencionou, há um módulo autônomo exec-sync

ATUALIZAÇÃO 2014-07-30

O ShellJS lib chegou. Considere esta é a melhor escolha por agora.


ATUALIZAÇÃO 2015-02-10

FINALMENTE! O NodeJS 0.12 suporta execSync nativamente.
Veja os documentos oficiais

Node.js (desde a versão 0.12 – assim por um tempo) suporta execSync :

 child_process.execSync(command[, options]) 

Agora você pode fazer isso diretamente:

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

e vai fazer o que você espera. (Padrões para canalizar os resultados de E / S para o processo pai). Note que você também pode spawnSync agora.

Veja biblioteca execSync .

É bastante fácil fazer com o node-ffi . Eu não recomendaria para processos de servidor, mas para utilitários de desenvolvimento geral faz as coisas. Instale a biblioteca.

 npm install node-ffi 

Exemplo de script:

 var FFI = require("node-ffi"); var libc = new FFI.Library(null, { "system": ["int32", ["string"]] }); var run = libc.system; run("echo $USER"); 

[EDIT junho 2012: Como obter 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')); 

Use o módulo ShellJS .

function exec sem fornecer callback.

Exemplo:

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

Há um excelente módulo para controle de stream no node.js chamado asyncblock . Se envolver o código em uma function for OK para o seu caso, a amostra a seguir pode ser considerada:

 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...'); }); 

Isso não é possível no Node.js, tanto child_process.spawn quanto child_process.exec foram construídos do zero para serem asynchronouss.

Para detalhes, consulte: https://github.com/ry/node/blob/master/lib/child_process.js

Se você realmente quiser ter esse bloqueio, coloque tudo o que precisa acontecer depois em um callback, ou construa sua própria fila para lidar com isso de uma forma bloqueada, eu suponho que você poderia usar o Async.js para essa tarefa.

Ou, no caso de você ter tempo demais para gastar, faça uma pesquisa no próprio Node.js.

Essa é a maneira mais fácil que encontrei:

exec-Sync : https://github.com/jeremyfa/node-exec-sync
(Não confunda com o execSync.)
Execute o comando shell de forma síncrona. Use isso para scripts de migration, programas cli, mas não para o código do servidor regular.

Exemplo:

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

Apenas para acrescentar que, embora existam poucos casos em que você deve usá-los, spawnSync / execFileSync / execSync foram adicionados ao node.js nestes commits: https://github.com/joyent/node/compare/d58c206862dc…e8df2676748e

Você pode conseguir isso usando fibras. Por exemplo, usando minha biblioteca Common Node , o código ficaria assim:

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

Eu me acostumo a implementar material "synchronous" no final da function de retorno de chamada. Não é muito bom, mas funciona. Se você precisar implementar uma sequência de execuções de linha de comando, precisará include o exec em alguma function nomeada e chamá-la recursivamente. Esse padrão parece ser útil para mim:

 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); } }); }; 

Eu tive um problema semelhante e acabei escrevendo uma extensão de nó para isso. Você pode verificar o repository git. É open source e gratuito e todas essas coisas boas!

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

ExecXI é uma extensão de nó escrita em C ++ para executar comandos shell um por um, gerando a saída do comando para o console em tempo real. As maneiras opcionais acorrentadas e desencadeadas estão presentes; significando que você pode escolher parar o script depois que um comando falhar (encadeado), ou você pode continuar como se nada tivesse acontecido!

Instruções de uso estão no arquivo ReadMe . Sinta-se à vontade para fazer solicitações de pull ou enviar problemas!

EDIT: No entanto, ele não retorna o stdout ainda … Apenas os envia em tempo real. Faz agora. Bem, acabei de liberar hoje. Talvez possamos construir sobre isso.

De qualquer forma, achei que valeria a pena mencionar isso.

você pode fazer operações de shell síncrono em nodejs da seguinte forma:

 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 /sc:\\usr\\docs\\")); 

EDIT – este exemplo é destinado a ambientes Windows, ajuste para suas próprias necessidades de linux se necessário

Na verdade, tive uma situação em que precisei executar vários comandos, um após o outro, a partir de um script de pré-instalação do package.json de uma maneira que funcionasse tanto no Windows quanto no Linux / OSX, portanto, não podia confiar em um módulo não-núcleo.

Então é isso que eu criei:

 #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() 

Você pode usá-lo assim:

 require('./cmds').exec ['grunt coffee', 'nodeunit test/tls-config.js'] 

EDIT: como apontado, isso não retorna a saída ou permite que você use o resultado dos comandos em um programa Node. Uma outra ideia para isso é usar backcalls do LiveScript. http://livescript.net/