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