javascript - script - shell node js
ejecuciĆ³n del comando de shell node.js (10)
Sincrónico de una sola línea:
require(''child_process'').execSync("echo ''hi''", function puts(error, stdout, stderr) { console.log(stdout) });
Todavía estoy tratando de captar los puntos más finos de cómo puedo ejecutar un comando de linux o windows shell y capturar el resultado dentro de node.js; en última instancia, quiero hacer algo como esto ...
//pseudocode
output = run_command(cmd, args)
La pieza importante es que la output
debe estar disponible para una variable (u objeto) de ámbito global. Intenté la siguiente función, pero por alguna razón, me imprimí undefined
en la consola ...
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" <------
Tengo problemas para entender dónde se rompe el código ... un prototipo muy simple de ese 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" <----
¿Alguien puede ayudarme a entender por qué try_this()
funciona, y run_cmd()
no? FWIW, necesito usar child_process.spawn
, porque child_process.exec
tiene un límite de buffer de child_process.exec
.
Resolución final
Estoy aceptando la respuesta de James White, pero este es el código exacto que funcionó para mí ...
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);
@ TonyO''Hagan es una respuesta comprensiva de shelljs
, pero me gustaría destacar la versión sincrónica de su respuesta:
var shell = require(''shelljs'');
var output = shell.exec(''netstat -rn'', {silent:true}).output;
console.log(output);
Aquí hay tres problemas que deben corregirse:
Lo primero es que está esperando un comportamiento sincrónico al usar stdout de forma asíncrona. Todas las llamadas en su función run_cmd
son asincrónicas, por lo que generarán el proceso secundario y regresarán inmediatamente independientemente de si algunos, todos o ninguno de los datos se han leído fuera de stdout. Como tal, cuando corres
console.log(foo.stdout);
obtienes lo que sea que esté almacenado en foo.stdout en este momento, y no hay garantía de lo que será porque el proceso de tu hijo aún podría estar ejecutándose.
En segundo lugar, stdout es una secuencia legible , por lo que 1) el evento de datos puede invocarse varias veces y 2) la devolución de llamada recibe un búfer, no una cadena. Fácil de remediar; solo cambia
foo = new run_cmd(
''netstat.exe'', [''-an''], function (me, data){me.stdout=data;}
);
dentro
foo = new run_cmd(
''netstat.exe'', [''-an''], function (me, buffer){me.stdout+=buffer.toString();}
);
para que convirtamos nuestro buffer en una cadena y anexar esa cadena a nuestra variable stdout.
En tercer lugar , solo puede saber que ha recibido todos los resultados cuando obtiene el evento ''final'', lo que significa que necesitamos otro oyente y devolución de llamada:
function run_cmd(cmd, args, cb, end) {
// ...
child.stdout.on(''end'', end);
}
Entonces, tu resultado final es este:
function run_cmd(cmd, args, cb, end) {
var spawn = require(''child_process'').spawn,
child = spawn(cmd, args),
me = this;
child.stdout.on(''data'', function (buffer) { cb(me, buffer) });
child.stdout.on(''end'', end);
}
// Run C:/Windows/System32/netstat.exe -an
var foo = new run_cmd(
''netstat.exe'', [''-an''],
function (me, buffer) { me.stdout += buffer.toString() },
function () { console.log(foo.stdout) }
);
En realidad, no está devolviendo nada de su función run_cmd.
function run_cmd(cmd, args, done) {
var spawn = require("child_process").spawn;
var child = spawn(cmd, args);
var result = { stdout: "" };
child.stdout.on("data", function (data) {
result.stdout += data;
});
child.stdout.on("end", function () {
done();
});
return result;
}
> foo = run_cmd("ls", ["-al"], function () { console.log("done!"); });
{ stdout: '''' }
done!
> foo.stdout
''total 28520...''
Funciona bien :)
Hay un conflicto variable en su función run_cmd
:
var me = this;
child.stdout.on(''data'', function(me, data) {
// me is overriden by function argument
cb(me, data);
});
Simplemente cámbialo a esto:
var me = this;
child.stdout.on(''data'', function(data) {
// One argument only!
cb(me, data);
});
Para ver los errores siempre agregue esto:
child.stderr.on(''data'', function(data) {
console.log( data );
});
EDITAR Su código falla porque está tratando de ejecutar dir
que no se proporciona como un programa independiente separado. Es un comando en el proceso de cmd
. Si desea jugar con el sistema de archivos use native require( ''fs'' )
.
Alternativamente (que no recomiendo) puede crear un archivo por lotes que luego puede ejecutar. Tenga en cuenta que el sistema operativo por defecto dispara archivos por lotes a través de cmd
.
La forma más simple es simplemente usar la lib de ShellJS ...
$ npm install [-g] shelljs
Ejemplo EXEC:
require(''shelljs/global'');
// Sync call to exec()
var version = exec(''node --version'', {silent:true}).output;
// Async call to exec()
exec(''netstat.exe -an'', function(status, output) {
console.log(''Exit status:'', status);
console.log(''Program output:'', output);
});
ShellJs.org admite muchos comandos de shell comunes asignados como funciones de NodeJS, que incluyen:
- gato
- discos compactos
- chmod
- cp
- dirs
- eco
- ejecutivo
- salida
- encontrar
- grep
- ln
- ls
- mkdir
- mv
- popd
- empujado
- pwd
- rm
- sed
- prueba
- cual
Tuve un problema similar y terminé escribiendo una extensión de nodo para esto. Puedes ver el repositorio de git. ¡Es de código abierto y gratuito y todas esas cosas buenas!
https://github.com/aponxi/npm-execxi
ExecXI es una extensión de nodo escrita en C ++ para ejecutar comandos de shell uno por uno, dando salida a la consola en tiempo real. Hay formas encadenadas y desencadenadas opcionales; lo que significa que puede optar por detener el script después de que falla un comando (encadenado), o puede continuar como si nada hubiera sucedido.
Las instrucciones de uso están en el archivo ReadMe . Siéntase libre de hacer solicitudes de extracción o enviar problemas!
Pensé que valía la pena mencionarlo.
Una versión promisificada de la respuesta más premiada:
runCmd: (cmd, args) => {
return new Promise((resolve, reject) => {
var spawn = require(''child_process'').spawn
var child = spawn(cmd, args)
var resp = ''''
child.stdout.on(''data'', function (buffer) { resp += buffer.toString() })
child.stdout.on(''end'', function () { resolve(resp) })
})
}
Usar:
runCmd(''ls'').then(ret => console.log(ret))
Una versión simplificada de la respuesta aceptada (tercer punto), acaba de funcionar para mí.
function run_cmd(cmd, args, callBack ) {
var spawn = require(''child_process'').spawn;
var child = spawn(cmd, args);
var resp = "";
child.stdout.on(''data'', function (buffer) { resp += buffer.toString() });
child.stdout.on(''end'', function() { callBack (resp) });
} // ()
Uso:
run_cmd( "ls", ["-l"], function(text) { console.log (text) });
run_cmd( "hostname", [], function(text) { console.log (text) });
Usé esto de manera más concisa:
var sys = require(''sys'')
var exec = require(''child_process'').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", puts);
funciona perfectamente :)