Выполнить и получить вывод команды оболочки в node.js

113

В node.js я хотел бы найти способ получить вывод команды терминала Unix. Есть какой-либо способ сделать это?

function getCommandOutput(commandString){
    // now how can I implement this function?
    // getCommandOutput("ls") should print the terminal output of the shell command "ls"
}
Андерсон Грин
источник
Это дубликат или он описывает что-то совершенно другое? stackoverflow.com/questions/7183307/…
Андерсон Грин
Это может вас заинтересовать.
Benekastah
Используйте npmjs.com/package/cross-spawn
Эндрю Костер,

Ответы:

143

Так я делаю это в проекте, над которым работаю сейчас.

var exec = require('child_process').exec;
function execute(command, callback){
    exec(command, function(error, stdout, stderr){ callback(stdout); });
};

Пример: получение пользователя git

module.exports.getGitUser = function(callback){
    execute("git config --global user.name", function(name){
        execute("git config --global user.email", function(email){
            callback({ name: name.replace("\n", ""), email: email.replace("\n", "") });
        });
    });
};
Ренато Гама
источник
3
Можно ли заставить эту функцию возвращать вывод команды? (Это то, что я пытался сделать.)
Андерсон Грин
1
вот что делает этот код. взгляните на пример редактирования, которое я только что сделал
Ренато Гама
2
@AndersonGreen Вы бы не хотели, чтобы функция возвращалась нормально с клавиатурой "return", потому что она выполняет команду оболочки асинхронно. В результате лучше передать обратный вызов с кодом, который должен выполняться после завершения команды оболочки.
Ник Маккарди
1
Ой, ваш первый образец игнорирует возможность ошибки при вызове этого обратного вызова. Интересно, что будет, stdoutесли возникнет ошибка. Надеюсь, детерминированный и задокументированный.
doug65536
31

Вы ищете child_process

var exec = require('child_process').exec;
var child;

child = exec(command,
   function (error, stdout, stderr) {
      console.log('stdout: ' + stdout);
      console.log('stderr: ' + stderr);
      if (error !== null) {
          console.log('exec error: ' + error);
      }
   });

Как указал Ренато, сейчас есть несколько синхронных пакетов exec, см. Sync-exec, который может быть больше тем, что вы ищете. Однако имейте в виду, что node.js разработан как однопоточный высокопроизводительный сетевой сервер, поэтому, если вы хотите использовать его для этого, держитесь подальше от чего-то вроде sync-exec, если вы не используете его только во время запуска. или что-то.

гексист
источник
1
В этом случае, как я могу получить результат выполнения команды? Это "stdout", который содержит вывод командной строки?
Андерсон Грин
Кроме того, можно ли сделать что-то подобное без использования обратного вызова?
Андерсон Грин
Правильно, stdout содержит вывод программы. И нет, без обратных вызовов это невозможно. Все в node.js ориентировано на неблокирование, то есть каждый раз, когда вы выполняете ввод-вывод, вы будете использовать обратные вызовы.
hexist
Обратите внимание: если вы ищете использование javascript для выполнения каких-то скриптовых вещей, когда вы действительно хотите ждать вывода и тому подобное, вы можете посмотреть на оболочку v8, d8
hexist
@hexist есть некоторые Syncметоды, изначально доступные, даже в этом случае ИМХО, этого следует избегать
Ренато Гама
30

Если вы используете node позже 7.6 и вам не нравится стиль обратного вызова, вы также можете использовать promisifyфункцию node-util с, async / awaitчтобы получить команды оболочки, которые читаются чисто. Вот пример принятого ответа с использованием этой техники:

const { promisify } = require('util');
const exec = promisify(require('child_process').exec)

module.exports.getGitUser = async function getGitUser () {
  const name = await exec('git config --global user.name')
  const email = await exec('git config --global user.email')
  return { name, email }
};

Это также дает дополнительное преимущество в виде возврата отклоненного обещания при неудачных командах, что может быть обработано try / catchвнутри асинхронного кода.

Ансикт
источник
Вы пробовали это? Я получаю { stdout: string, stderr: string }в результате заawait exec(...)
fwoelffel
1
Да, я должен был уточнить, что это дает вам полный вывод оболочки, включая stdout и stderr. Если вы хотите , только выход, вы могли бы изменить последнюю строку: return { name: name.stdout.trim(), email: email.stdout.trim() }.
Ансикт
16

Благодаря ответу Ренато я создал действительно простой пример:

const exec = require('child_process').exec

exec('git config --global user.name', (err, stdout, stderr) => console.log(stdout))

Он просто напечатает ваше глобальное имя пользователя git :)

Дамьян Павлица
источник
11

Требования

Для этого потребуется Node.js 7 или новее с поддержкой Promises и Async / Await.

Решение

Создайте функцию-оболочку, которая использует обещания для управления поведением child_process.execкоманды.

Объяснение

Используя промисы и асинхронную функцию, вы можете имитировать поведение оболочки, возвращающей результат, не впадая в ад обратных вызовов и с довольно аккуратным API. Используя awaitключевое слово, вы можете создать сценарий, который легко читается, но при этом может выполнять свою работу child_process.exec.

Пример кода

const childProcess = require("child_process");

/**
 * @param {string} command A shell command to execute
 * @return {Promise<string>} A promise that resolve to the output of the shell command, or an error
 * @example const output = await execute("ls -alh");
 */
function execute(command) {
  /**
   * @param {Function} resolve A function that resolves the promise
   * @param {Function} reject A function that fails the promise
   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
   */
  return new Promise(function(resolve, reject) {
    /**
     * @param {Error} error An error triggered during the execution of the childProcess.exec command
     * @param {string|Buffer} standardOutput The result of the shell command execution
     * @param {string|Buffer} standardError The error resulting of the shell command execution
     * @see https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
     */
    childProcess.exec(command, function(error, standardOutput, standardError) {
      if (error) {
        reject();

        return;
      }

      if (standardError) {
        reject(standardError);

        return;
      }

      resolve(standardOutput);
    });
  });
}

использование

async function main() {
  try {
    const passwdContent = await execute("cat /etc/passwd");

    console.log(passwdContent);
  } catch (error) {
    console.error(error.toString());
  }

  try {
    const shadowContent = await execute("cat /etc/shadow");

    console.log(shadowContent);
  } catch (error) {
    console.error(error.toString());
  }
}

main();

Пример вывода

root:x:0:0::/root:/bin/bash
[output trimmed, bottom line it succeeded]

Error: Command failed: cat /etc/shadow
cat: /etc/shadow: Permission denied

Попробуйте онлайн.

Repl.it .

Внешние ресурсы

Обещания .

child_process.exec.

Node.js поддержка таблицы .

Амин НАИРИ
источник