HOWTO · Go
So führen Sie einen Shell-Befehl in Go aus
Erfahren Sie, wie Sie externe Programme aus Go mit os/exec ausführen, Ausgaben erfassen, Fehler behandeln, Argumente übergeben und ein Arbeitsverzeichnis für einen Befehl festlegen. Shell-Funktionen erfordern das explizite Aufrufen einer Shell.
Auf dieser Seite
Um ein externes Programm aus Go auszuführen, verwenden Sie das Paket os/exec der Standardbibliothek. Es startet die benannte ausführbare Datei direkt; es führt nicht implizit eine Shell aus. Shell-Funktionen wie Pipes, Umleitung, Variablenerweiterung und Platzhalter werden daher nicht angewendet. Wenn eine Aufgabe diese Funktionen benötigt, rufen Sie eine Shell explizit auf und übergeben Sie ihr Skript als Argument, wobei Sie darauf achten, keinen nicht vertrauenswürdigen Text in dieses Skript einzufügen.
Einen Befehl mit os/exec ausführen
Erstellen Sie einen Befehl mit exec.Command und rufen Sie dann eine Methode wie Output auf, um ihn zu starten und seine Standardausgabe zu sammeln. Das erste Argument benennt die ausführbare Datei, und die übrigen Argumente werden an dieses Programm übergeben. Dieses vollständige Programm startet sich selbst als Kindprozess mit einem Argument. Das Kind gibt eine feste Zeile aus, und der Elternprozess erfasst diese Standardausgabe und schreibt sie in seine eigene Standardausgabe. Das Programm gibt die Zeile des Kindes über den Elternprozess aus.
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "child" {
fmt.Println("hello from child")
return
}
cmd := exec.Command(os.Args[0], "child")
output, err := cmd.Output()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Print(string(output))
}
hello from child
Hier identifiziert os.Args[0] die aktuelle ausführbare Datei, sodass das Beispiel nicht davon abhängt, dass ein separates Hilfsprogramm installiert ist. Ersetzen Sie es in einer Anwendung durch die benötigte ausführbare Datei, etwa git oder go, und geben Sie die Argumente dieses Programms separat an.
Ausgabe erfassen und Fehler behandeln
Prüfen Sie den von Output oder CombinedOutput zurückgegebenen Fehler, bevor Sie das Ergebnis verwenden. Ein Fehler beim Starten eines Programms, etwa eine ausführbare Datei, die nicht gefunden werden kann, unterscheidet sich von einem Programm, das startet und mit einem von null verschiedenen Status endet. Im letzteren Fall ist der Fehler in der Regel ein *exec.ExitError; untersuchen Sie ihn, wenn der Exit-Status wichtig ist. Der Typ Cmd ermöglicht es Ihnen auch, Streams direkt zu verbinden: Setzen Sie cmd.Stdout oder cmd.Stderr auf einen Writer, wenn die Ausgabe dorthin gesendet werden soll, statt in einem Byte-Slice gesammelt zu werden.
Verwenden Sie Output, wenn die Standardausgabe die Daten sind, die Ihr Programm benötigt. Verwenden Sie CombinedOutput, wenn Sie auch die Standardfehlerausgabe in den zurückgegebenen Bytes benötigen; die beiden Streams werden kombiniert, sodass ihre relative Reihenfolge keine zuverlässige Möglichkeit ist, getrennte Streams zu rekonstruieren. Wenn Diagnosen getrennt bleiben müssen, weisen Sie cmd.Stdout und cmd.Stderr separate Writer zu. Behandeln und melden Sie Fehler an der Stelle, an der der Aufrufer entscheiden kann, ob er es erneut versucht, zurückkehrt oder fortfährt; einen Fehler auszudrucken und den Befehl dann als erfolgreich zu behandeln, kann einen fehlgeschlagenen Vorgang verbergen.
Argumente an einen Befehl übergeben
Übergeben Sie jedes Argument als eigenen String nach dem Namen der ausführbaren Datei, zum Beispiel exec.Command("grep", "-n", pattern, filename). Go fügt diese Werte nicht zu einem Shell-Befehl zusammen und interpretiert Leerzeichen, Anführungszeichen, Pipes oder Umleitungszeichen nicht für Sie. Ein Dateiname mit Leerzeichen bleibt ein Argument, wenn er als ein String angegeben wird. Dies vermeidet das Shell-Parsing, validiert die Eingabe für das aufgerufene Programm jedoch nicht: Ein Argument kann für dieses Programm immer noch eine besondere Bedeutung haben, also validieren Sie Werte gemäß der eigenen Schnittstelle des Befehls.
Weisen Sie für Eingabe- und Ausgabestreams einen io.Reader an cmd.Stdin und Writer an cmd.Stdout oder cmd.Stderr zu und rufen Sie dann Run auf. Die obige Beispiel-Programmdatei verwendet Output, weil sie nur ein kurzes Ergebnis erfassen muss. Verwenden Sie Run, wenn Sie Streams verbinden möchten und die Standardausgabe nicht als Rückgabewert sammeln müssen. Die ausführbare Datei muss dem Prozess zur Verfügung stehen, und ihre Optionen können je nach Betriebssystem unterschiedlich sein.
Einen Befehl in einem anderen Verzeichnis ausführen
Setzen Sie cmd.Dir, bevor Sie den Befehl starten, um sein Arbeitsverzeichnis zu wählen. Setzen Sie zum Beispiel nach dem Erstellen eines Befehls cmd.Dir = projectDir und rufen Sie dann Output, CombinedOutput oder Run auf. Das Verzeichnis muss existieren und für den Prozess zugänglich sein. Ein relatives cmd.Dir wird relativ zum aktuellen Arbeitsverzeichnis des Go-Prozesses aufgelöst; verwenden Sie einen absoluten Pfad, wenn das Startverzeichnis des Aufrufers variieren kann. Diese Einstellung ändert das Verzeichnis des Kindprozesses und ändert nicht das eigene Arbeitsverzeichnis des Go-Prozesses.