Ainda estou tentando entender os pontos mais delicados de como posso executar um comando linux ou windows shell e capturar a saída em node.js; no final das contas, eu quero fazer algo assim ...
//pseudocode
output = run_command(cmd, args)
A parte importante é que output
deve estar disponível para uma variável com escopo global (ou objeto). Tentei a seguinte função, mas por algum motivo, fui undefined
impresso no console ...
function run_cmd(cmd, args, cb) {
var spawn = require('child_process').spawn
var child = spawn(cmd, args);
var me = this;
child.stdout.on('data', function(me, data) {
cb(me, data);
});
}
foo = new run_cmd('dir', ['/B'], function (me, data){me.stdout=data;});
console.log(foo.stdout); // yields "undefined" <------
Estou tendo problemas para entender onde o código quebra acima ... um protótipo muito simples desse modelo funciona ...
function try_this(cmd, cb) {
var me = this;
cb(me, cmd)
}
bar = new try_this('guacamole', function (me, cmd){me.output=cmd;})
console.log(bar.output); // yields "guacamole" <----
Alguém pode me ajudar a entender por que try_this()
funciona e run_cmd()
não funciona? FWIW, preciso usar child_process.spawn
, porque child_process.exec
tem um limite de buffer de 200 KB .
Resolução Final
Estou aceitando a resposta de Tiago White, mas este é o código exato que funcionou para mim ...
function cmd_exec(cmd, args, cb_stdout, cb_end) {
var spawn = require('child_process').spawn,
child = spawn(cmd, args),
me = this;
me.exit = 0; // Send a cb to set 1 when cmd exits
me.stdout = "";
child.stdout.on('data', function (data) { cb_stdout(me, data) });
child.stdout.on('end', function () { cb_end(me) });
}
foo = new cmd_exec('netstat', ['-rn'],
function (me, data) {me.stdout += data.toString();},
function (me) {me.exit = 1;}
);
function log_console() {
console.log(foo.stdout);
}
setTimeout(
// wait 0.25 seconds and print the output
log_console,
250);
fonte
me.stdout = "";
emcmd_exec()
para evitar concatenaçãoundefined
para o início do resultado.Respostas:
Existem três problemas aqui que precisam ser corrigidos:
A primeira é que você está esperando um comportamento síncrono ao usar o stdout de forma assíncrona. Todas as chamadas em sua
run_cmd
função são assíncronas, portanto, ele gerará o processo filho e retornará imediatamente, independentemente de alguns, todos ou nenhum dos dados terem sido lidos no stdout. Como tal, quando você executavocê obtém o que quer que esteja armazenado em foo.stdout no momento, e não há garantia do que será, porque seu processo filho ainda pode estar em execução.
O segundo é que stdout é um fluxo legível , portanto 1) o evento de dados pode ser chamado várias vezes e 2) o retorno de chamada recebe um buffer, não uma string. Fácil de remediar; Apenas mude
para dentro
para que possamos converter nosso buffer em uma string e anexar essa string à nossa variável stdout.
Em terceiro lugar, você só pode saber que recebeu todas as saídas ao obter o evento 'final', o que significa que precisamos de outro ouvinte e retorno de chamada:
Então, seu resultado final é este:
fonte
this.stdout = "";
dentro darun()
função, caso contrário, seuconsole.log(foo.sdtout);
será prefixado comundefined
.Uma versão simplificada da resposta aceita (terceiro ponto) funcionou para mim.
Uso:
fonte
child.stdout.on('close', (errCode) => { console.log(errCode) } )
Usei isso de forma mais concisa:
funciona perfeitamente. :)
fonte
sys.puts()
foi descontinuado em 2011 (com Node.js v0.2.3). Você deve usar em seuconsole.log()
lugar.A maneira mais simples é apenas usar a biblioteca ShellJS ...
Exemplo EXEC:
ShellJs.org suporta muitos comandos shell comuns mapeados como funções NodeJS, incluindo:
fonte
shell.exec("foo.sh arg1 arg2 ... ")
. Seufoo.sh
script pode fazer referência a eles usando$1
,$2
... etc.Eu tive um problema semelhante e acabei escrevendo uma extensão de nó para isso. Você pode verificar o repositório git. É open source e gratuito e todas essas coisas boas!
https://github.com/aponxi/npm-execxi
As instruções de uso estão no arquivo LeiaMe . Sinta-se à vontade para fazer solicitações de pull ou enviar problemas!
Achei que valia a pena mencionar isso.
fonte
@ TonyO'Hagan é uma
shelljs
resposta abrangente , mas, gostaria de destacar a versão síncrona de sua resposta:fonte
One-liner síncrono:
require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });
fonte
Há um conflito de variável em sua
run_cmd
função:Simplesmente mude para este:
Para ver os erros, sempre adicione:
EDITAR Seu código falha porque você está tentando executar o
dir
que não é fornecido como um programa autônomo separado. É um comando emcmd
andamento. Se você quiser brincar com o sistema de arquivos, use o nativorequire( 'fs' )
.Como alternativa (o que eu não recomendo), você pode criar um arquivo em lote que pode ser executado. Observe que o sistema operacional, por padrão, dispara arquivos em lote via
cmd
.fonte
C:\Windows\System32\netstat.exe
, isso ainda não produz resultados ... Minha sintaxe exata erafoo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;});
... Eu também tentei o caminho completo sem sucesso até agoraNa verdade, você não está retornando nada da função run_cmd.
Funciona muito bem. :)
fonte
return
seja necessário, desde que você defina corretamente os atributos do objetoUma versão prometida da resposta mais premiada:
Usar:
fonte