Jalankan dan dapatkan output dari perintah shell di node.js

113

Di node.js, saya ingin menemukan cara untuk mendapatkan output dari perintah terminal Unix. Apakah ada cara untuk melakukan ini?

function getCommandOutput(commandString){
    // now how can I implement this function?
    // getCommandOutput("ls") should print the terminal output of the shell command "ls"
}
Anderson Green
sumber
Apakah ini duplikat, atau apakah itu menjelaskan sesuatu yang sama sekali berbeda? stackoverflow.com/questions/7183307/…
Anderson Green
Ini mungkin menarik bagi Anda.
benekastah
Gunakan npmjs.com/package/cross-spawn
Andrew Koster

Jawaban:

142

Itulah cara saya melakukannya dalam proyek yang saya kerjakan sekarang.

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

Contoh: Mengambil pengguna 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", "") });
        });
    });
};
Renato Gama
sumber
3
Apakah mungkin untuk membuat fungsi ini mengembalikan keluaran perintah? (Itulah yang saya coba lakukan.)
Anderson Green
1
itulah yang kode itu lakukan. lihat contoh pada pengeditan yang baru saja saya buat
Renato Gama
2
@AndersonGreen Anda tidak ingin fungsi kembali normal dengan keyboard "return", karena menjalankan perintah shell secara asynchronous. Akibatnya, lebih baik meneruskan callback dengan kode yang harus dijalankan saat perintah shell selesai.
Nick McCurdy
1
Aduh, sampel pertama Anda mengabaikan kemungkinan error saat memanggil callback tersebut. Saya bertanya-tanya apa yang terjadi stdoutjika ada kesalahan. Semoga deterministik dan terdokumentasi.
doug65536
31

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

Seperti yang ditunjukkan oleh Renato, ada beberapa paket exec sinkron di luar sana sekarang juga, lihat sync-exec yang mungkin lebih sesuai dengan yang Anda cari. Perlu diingat, node.js dirancang untuk menjadi server jaringan berkinerja tinggi berulir tunggal, jadi jika itu yang ingin Anda gunakan, jauhi hal-hal sync-exec kecuali jika Anda hanya menggunakannya selama startup atau sesuatu.

hexist
sumber
1
Dalam hal ini, bagaimana saya bisa mendapatkan keluaran dari perintah? Apakah "stdout" yang berisi keluaran baris perintah?
Anderson Green
Juga, apakah mungkin untuk melakukan hal serupa tanpa menggunakan callback?
Anderson Green
Benar, stdout berisi keluaran dari program. Dan tidak, tidak mungkin melakukannya tanpa panggilan balik. Segala sesuatu di node.js berorientasi pada non-pemblokiran, artinya setiap kali Anda melakukan IO, Anda akan menggunakan callback.
hexist
Perhatikan bahwa jika Anda mencari menggunakan javascript untuk melakukan scripty semacam hal di mana Anda benar-benar ingin menunggu keluaran dan hal semacam itu, Anda mungkin melihat v8 shell, d8
hexist
@hexist ada beberapa Syncmetode yang tersedia secara asli, meskipun demikian IMHO itu harus dihindari
Renato Gama
29

Jika Anda menggunakan node lebih baru dari 7.6 dan Anda tidak menyukai gaya panggilan balik, Anda juga dapat menggunakan promisifyfungsi node-util dengan async / awaituntuk mendapatkan perintah shell yang terbaca dengan rapi. Berikut adalah contoh jawaban yang diterima, menggunakan teknik ini:

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

Ini juga memiliki keuntungan tambahan yaitu mengembalikan janji yang ditolak pada perintah yang gagal, yang dapat ditangani dengan try / catchdi dalam kode async.

Ansikt
sumber
Sudahkah kamu mencobanya? Saya mendapatkan { stdout: string, stderr: string }hasil untukawait exec(...)
fwoelffel
1
Ya, saya seharusnya menjelaskan bahwa ini memberi Anda keluaran shell penuh , termasuk stdout dan stderr. Jika Anda ingin hanya output, Anda bisa mengubah baris terakhir ke: return { name: name.stdout.trim(), email: email.stdout.trim() }.
Ansikt
16

Berkat jawaban Renato, saya telah membuat contoh yang sangat mendasar:

const exec = require('child_process').exec

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

Ini hanya akan mencetak nama pengguna git global Anda :)

Damjan Pavlica
sumber
11

Persyaratan

Ini akan membutuhkan Node.js 7 atau yang lebih baru dengan dukungan untuk Promises dan Async / Await.

Larutan

Buat fungsi pembungkus yang memanfaatkan janji untuk mengontrol perilaku child_process.execperintah.

Penjelasan

Dengan menggunakan promise dan fungsi asynchronous, Anda bisa meniru perilaku shell yang mengembalikan output, tanpa jatuh ke neraka panggilan balik dan dengan API yang cukup rapi. Dengan menggunakan awaitkata kunci, Anda dapat membuat skrip yang dapat dibaca dengan mudah, namun tetap dapat menyelesaikan pekerjaan child_process.exec.

Contoh kode

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

Pemakaian

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

Output Sampel

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

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

Cobalah secara online.

Repl.it .

Sumber daya eksternal

Janji .

child_process.exec.

Node.js dukungan meja .

Amin NAIRI
sumber