Виконати та отримати вихід команди оболонки в 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

Відповіді:


142

Саме так я роблю це в проекті, над яким я зараз працюю.

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 орієнтоване на те, щоб не блокувати, тобто кожен раз, коли ви робите IO, ви будете використовувати зворотні дзвінки.
— гексист

Зауважте, що якщо ви шукаєте за допомогою JavaScript для створення сценаріїв, які ви хочете чекати на виході, і подібні речі, ви можете подивитися на оболонку v8, d8
— гексист

@hexist Є кілька Syncметодів, які існують у продажу, навіть тому IMHO цього слід уникати
— Ренато Гама

29

Якщо ви використовуєте вузол пізніше 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всередині коду async.


Ви пробували це? Я отримую { stdout: string, stderr: string }результатawait exec(...)
— fwoelffel

1
Так, я мав би уточнити, що це дає вам повний вихід оболонки, включаючи як stdout, так і stderr. Якщо ви хочете , тільки вихід, ви могли б змінити останній рядок: return { name: name.stdout.trim(), email: email.stdout.trim() }.
— Ansikt

16

Завдяки відповіді Ренато я створив дійсно основний приклад:

const exec = require('child_process').exec

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

Він просто надрукує ваше глобальне ім'я користувача git :)


11

Вимоги

Для цього знадобиться Node.js 7 або пізнішої версії з підтримкою Обіцяння та Асинхрон / Очікування.

Рішення

Створіть функцію обгортки, яка використовує обіцянки контролювати поведінку 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 підтримка таблиці .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.