Выполнение команды node.js - программирование
Подтвердить что ты не робот

Выполнение команды node.js

Я все еще пытаюсь понять тонкости того, как я могу запустить команду оболочки linux или windows и выводить вывод в node.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);
4b9b3361

Ответ 1

Здесь необходимо устранить три проблемы:

Первый заключается в том, что вы ожидаете синхронного поведения при асинхронном использовании stdout. Все вызовы в вашей функции run_cmd являются асинхронными, поэтому он будет порождать дочерний процесс и немедленно возвращаться независимо от того, были ли считаны некоторые, все или никакие данные из stdout. Таким образом, при запуске

console.log(foo.stdout);

вы получаете все, что происходит в настоящее время в foo.stdout, и нет гарантии, что это будет, потому что ваш дочерний процесс все еще может работать.

Второй - это то, что 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) }
);

Ответ 2

Упрощенная версия принятого ответа (третий пункт), просто сработала для меня.

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

Ответ 3

Самый простой способ - просто использовать оболочку ShellJS...

$ npm install [-g] shelljs

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 поддерживает множество общих команд оболочки, отображаемых как функции NodeJS, включая:

  • кошка
  • кд
  • CHMOD
  • ф
  • каталоги
  • эхо
  • Exec
  • Выход
  • найти
  • Grep
  • пер
  • Ls
  • MkDir
  • мв
  • POPD
  • Pushd
  • PWD
  • гт
  • СЕПГ
  • тест
  • , который

Ответ 4

Я использовал это более кратко:

var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", puts);

работает отлично.:)

Ответ 5

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

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

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

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

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

Ответ 6

@TonyO'Hagan является компрессионным ответом shelljs, но я хотел бы выделить синхронную версию его ответа:

var shell = require('shelljs');
var output = shell.exec('netstat -rn', {silent:true}).output;
console.log(output);

Ответ 7

Синхронный однострочный:

require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });

Ответ 8

В вашей функции run_cmd есть переменный конфликт:

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

РЕДАКТИРОВАТЬ. Вы не выполняете код, потому что пытаетесь запустить dir, который не предоставляется как отдельная отдельная программа. Это команда в процессе cmd. Если вы хотите играть с файловой системой, используйте native require( 'fs' ).

В качестве альтернативы (который я не рекомендую) вы можете создать командный файл, который затем можно запустить. Обратите внимание, что ОС по умолчанию запускает пакетные файлы через cmd.

Ответ 9

Вы ничего не возвращаете из своей функции 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...'

Хорошо работает.:)

Ответ 10

Обещаемая версия наиболее выдающегося ответа:

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