Führen Sie die Ausgabe eines Shell-Befehls in node.js aus und rufen Sie sie ab

113

In einer node.js möchte ich einen Weg finden, um die Ausgabe eines Unix-Terminalbefehls zu erhalten. Gibt es eine Möglichkeit, dies zu tun?

function getCommandOutput(commandString){
    // now how can I implement this function?
    // getCommandOutput("ls") should print the terminal output of the shell command "ls"
}
Anderson Green
quelle
Ist das ein Duplikat oder beschreibt es etwas völlig anderes? stackoverflow.com/questions/7183307/…
Anderson Green
Das könnte dich interessieren.
Benekastah
Verwenden Sie npmjs.com/package/cross-spawn
Andrew Koster

Antworten:

142

So mache ich das in einem Projekt, an dem ich gerade arbeite.

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

Beispiel: Git-Benutzer abrufen

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
quelle
3
Ist es möglich, dass diese Funktion die Ausgabe des Befehls zurückgibt? (Das habe ich versucht.)
Anderson Green
1
Das ist es, was dieser Code tut. Schauen Sie sich das Beispiel der Bearbeitung an, die ich gerade vorgenommen habe
Renato Gama
2
@AndersonGreen Sie möchten nicht, dass die Funktion mit der "return" -Tastatur normal zurückgegeben wird, da der Shell-Befehl asynchron ausgeführt wird. Daher ist es besser, einen Rückruf mit Code zu übergeben, der ausgeführt werden soll, wenn der Shell-Befehl abgeschlossen ist.
Nick McCurdy
1
Autsch, Ihr erstes Beispiel ignoriert die Möglichkeit eines Fehlers, wenn es diesen Rückruf aufruft. Ich frage mich, was passiert, stdoutwenn ein Fehler vorliegt. Hoffentlich deterministisch und dokumentiert.
Doug65536
31

Sie suchen nach 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);
      }
   });

Wie Renato hervorhob, gibt es jetzt auch einige synchrone Exec-Pakete, siehe Sync-Exec , die möglicherweise mehr das sind, wonach Sie suchen. Beachten Sie jedoch, dass node.js als Hochleistungs-Netzwerkserver mit einem Thread konzipiert ist. Wenn Sie ihn also verwenden möchten, sollten Sie sich von Sync-Exec-Dingen fernhalten, es sei denn, Sie verwenden ihn nur während des Startvorgangs oder so.

Hexist
quelle
1
Wie kann ich in diesem Fall die Ausgabe des Befehls erhalten? Ist "stdout" die Befehlszeilenausgabe?
Anderson Green
Ist es auch möglich, etwas Ähnliches zu tun, ohne einen Rückruf zu verwenden?
Anderson Green
Richtig, stdout enthält die Ausgabe des Programms. Und nein, ohne Rückrufe ist das nicht möglich. Alles in node.js ist darauf ausgerichtet, nicht zu blockieren, dh jedes Mal, wenn Sie E / A ausführen, werden Sie Rückrufe verwenden.
Hexist
Beachten Sie, dass Sie, wenn Sie Javascript verwenden möchten, um scripty Dinge zu tun, bei denen Sie wirklich auf die Ausgabe und dergleichen warten möchten, möglicherweise die v8-Shell, d8
hexist
@hexist gibt es einige SyncMethoden nativ verfügbar, auch so sollte es meiner Meinung nach vermieden werden
Renato Gama
29

Wenn Sie den Knoten später als 7.6 verwenden und den Rückrufstil nicht mögen, können Sie auch die promisifyFunktion von node-util verwenden async / await, um Shell-Befehle abzurufen, die sauber gelesen werden. Hier ist ein Beispiel für die akzeptierte Antwort mit dieser Technik:

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

Dies hat auch den zusätzlichen Vorteil, dass ein abgelehntes Versprechen für fehlgeschlagene Befehle zurückgegeben wird, das try / catchinnerhalb des asynchronen Codes verarbeitet werden kann.

Ansikt
quelle
Hast du das versucht? Ich bekomme { stdout: string, stderr: string }als Ergebnis für dieawait exec(...)
fwoelffel
1
Ja, ich hätte klarstellen sollen, dass Sie damit die vollständige Shell-Ausgabe erhalten, einschließlich stdout und stderr. Wenn Sie nur die Ausgabe möchten, können Sie die letzte Zeile in: ändern return { name: name.stdout.trim(), email: email.stdout.trim() }.
Ansikt
16

Dank der Antwort von Renato habe ich ein wirklich einfaches Beispiel erstellt:

const exec = require('child_process').exec

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

Es wird nur Ihr globaler Git-Benutzername gedruckt :)

Damjan Pavlica
quelle
11

Bedarf

Dies erfordert Node.js 7 oder höher mit Unterstützung für Promises und Async / Await.

Lösung

Erstellen Sie eine Wrapper-Funktion, die Versprechen nutzt, um das Verhalten des child_process.execBefehls zu steuern .

Erläuterung

Mit Versprechungen und einer asynchronen Funktion können Sie das Verhalten einer Shell nachahmen, die die Ausgabe zurückgibt, ohne in eine Callback-Hölle zu geraten, und mit einer hübschen, ordentlichen API. Mit dem awaitSchlüsselwort können Sie ein Skript erstellen, das leicht zu lesen ist und dennoch die Arbeit child_process.execerledigt.

Codebeispiel

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

Verwendung

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

Beispielausgabe

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

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

Probieren Sie es online aus.

Repl.it .

Externe Ressourcen

Versprechen .

child_process.exec.

Node.js Support-Tabelle .

Amin NAIRI
quelle