узел.выполнение команды оболочки js
я все еще пытаюсь понять тонкости того, как я могу запустить команду оболочки linux или windows и захватить вывод в узле.js; в конечном счете, я хочу сделать что-то вроде этого...
//pseudocode
output = run_command(cmd, args)
важно то, что output должен быть доступен для переменной (или объекта) с глобальной областью действия. Я попробовал следующую функцию, но по какой-то причине я получаю undefined печать на консоль...
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" <------
у меня возникли проблемы с пониманием, где код ломается выше... очень простой прототип этой модели работает...
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" <----
может кто-нибудь помочь мне понять, почему try_this() работает, а run_cmd() не? FWIW, мне нужно использовать child_process.spawn, потому что child_process.exec имеет предел буфера 200кб.
Окончательное Решение
Я принимаю ответ Джеймса Уайта, но это точный код, который работал для меня...
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);
10 ответов:
здесь есть три проблемы, которые необходимо исправить:
первый это то, что вы ожидаете синхронного поведения при использовании stdout асинхронно. Все звонки в вашем
run_cmdфункция асинхронна, поэтому она будет порождать дочерний процесс и немедленно возвращаться независимо от того, были ли некоторые, все или ни один из данных считаны из stdout. Как таковой, когда вы бежитеconsole.log(foo.stdout);вы получаете все, что будет храниться в foo.stdout в the момент, и нет никакой гарантии, что это будет, потому что ваш ребенок процесс все еще может быть запущен.
второй заключается в том, что stdout является читаемый поток, поэтому 1) событие данных может быть вызвано несколько раз, и 2) обратный вызов задается буфером, а не строкой. Легко исправить, просто замените
foo = new run_cmd( 'netstat.exe', ['-an'], function (me, data){me.stdout=data;} );на
foo = new run_cmd( 'netstat.exe', ['-an'], function (me, buffer){me.stdout+=buffer.toString();} );так что мы преобразуем наш буфер в строку и добавим эту строку в наш stdout переменная.
третий это то, что вы можете только знать, что вы получили все выходные данные, когда вы получаете событие "end", что означает, что нам нужен другой слушатель и обратный вызов:
function run_cmd(cmd, args, cb, end) { // ... child.stdout.on('end', end); }Итак, ваш окончательный результат таков:
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) } );
упрощенный вариант принятого ответа (третий пункт), просто работал для меня.
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) }); } // ()использование:
run_cmd( "ls", ["-l"], function(text) { console.log (text) }); run_cmd( "hostname", [], function(text) { console.log (text) });
самый простой способ-просто использовать shelljs lib ...
$ npm install [-g] shelljsEXEC пример:
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 поддерживает множество общих команд оболочки, отображаемых как функции NodeJS
я использовал это более лаконично :
var sys = require('sys') var exec = require('child_process').exec; function puts(error, stdout, stderr) { sys.puts(stdout) } exec("ls -la", puts);он отлично работает. :)
У меня была аналогичная проблема, и я закончил писать расширение узла для этого. Вы можете проверить репозиторий Git. Это с открытым исходным кодом и бесплатно и все, что хороший материал !
https://github.com/aponxi/npm-execxi
ExecXI представляет собой узел расширения, написанные на C++, чтобы выполнить команды shell один за другим, выводя выходные данные команды на консоль в в реальном времени. Необязательно прикованный, и раскованных способов присутствуют; смысл что вы можете выбрать чтобы остановить скрипт, после того, как команда не (последовательно), или вы можете продолжать, как будто ничего не произошло !
инструкции по использованию находятся в ReadMe file. Не стесняйтесь делать запросы на вытягивание или отправлять вопросы!
Я подумал, что стоит упомянуть об этом.
@TonyO Хаган является comprehrensive
shelljsответ, но, я хотел бы выделить синхронную версию его ответа:var shell = require('shelljs'); var output = shell.exec('netstat -rn', {silent:true}).output; console.log(output);
синхронно одну строчку:
require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });
есть переменный конфликт в вашем :
var me = this; child.stdout.on('data', function(me, data) { // me is overriden by function argument cb(me, data); });просто измените его на это:
var me = this; child.stdout.on('data', function(data) { // One argument only! cb(me, data); });чтобы увидеть ошибки Всегда добавляйте это:
child.stderr.on('data', function(data) { console.log( data ); });EDIT ты код не удается, потому что вы пытаетесь запустить
dirчто это не предоставляется как отдельная автономная программа. Это команда, в
на самом деле вы ничего не возвращаете из своей функции 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...'работает просто отлично. :)
обещанная версия наиболее награжденного ответа:
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) }) }) }использование:
runCmd('ls').then(ret => console.log(ret))
Comments