116 votes

Exécuter une commande shell en Go

Je cherche à exécuter une commande shell en Go et à obtenir le résultat sous forme de chaîne de caractères dans mon programme. J'ai vu la commande Code Rosetta version :

package main
import "fmt"
import "exec"

func main() {
  cmd, err := exec.Run("/bin/ls", []string{"/bin/ls"}, []string{}, "", exec.DevNull, exec.PassThrough, exec.PassThrough)
  if (err != nil) {
    fmt.Println(err)
    return
  }
  cmd.Close()

Mais cela ne capture pas le standard out ou err de manière à ce que je puisse y accéder de manière programmatique - ils s'affichent toujours dans les stdout / stderr normaux. J'ai vu que l'utilisation de Pipe en tant que out ou err pourrait aider ailleurs, mais il n'y a pas d'exemple de la façon de le faire. Des idées ?

1voto

Clare Chu Points 189
import (
    "github.com/go-cmd/cmd"
)

const DefaultTimeoutTime = "1m"

func RunCMD(name string, args ...string) (err error, stdout, stderr []string) {
    c := cmd.NewCmd(name, args...)
    s := <-c.Start()
    stdout = s.Stdout
    stderr = s.Stderr
    return
}

aller tester

import (
    "fmt"
    "gotest.tools/assert"
    "testing"
)

func TestRunCMD(t *testing.T) {
    err, stdout, stderr := RunCMD("kubectl", "get", "pod", "--context", "cluster")
    assert.Equal(t, nil, err)
    for _, out := range stdout {
        fmt.Println(out)
    }
    for _, err := range stderr {
        fmt.Println(err)
    }
}

1voto

IStranger Points 1152

Si vous voulez exécuter un script de longue durée de manière asynchrone avec la progression de l'exécution, vous pouvez capturer la sortie de la commande à l'aide de la fonction io.MultiWriter et le transmettre à stdout/stderr :

import (
    "fmt"
    "io"
    "os"
    "os/exec"
)

var stdoutBuf, stderrBuf bytes.Buffer

cmd := exec.Command("/some-command")

cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)

err := cmd.Start()  // Starts command asynchronously

if err != nil {
    fmt.Printf(err.Error())
}

0voto

Tony Veijalainen Points 2579

Je n'ai pas réussi à faire fonctionner l'exemple Rosetta dans mon Windows Go. Finalement, j'ai réussi à dépasser l'ancien format du sous-processus avec cette commande pour lancer outfile dans notepad sous Windows. Le paramètre constant wait mentionné dans un manuel n'existait pas, j'ai donc laissé Wait de côté car l'utilisateur fermera le programme lui-même ou le laissera ouvert pour le réutiliser.

p, err := os.StartProcess(`c:\windows\system32\notepad.EXE`,
    []string{`c:\windows\system32\notepad.EXE`, outfile},
    &os.ProcAttr{Env: nil, Dir: "", Files:  []*os.File{os.Stdin, os.Stdout, os.Stderr}})

Vous devez remplacer os.Stdout par os.Pipe comme dans la réponse précédente.

EDIT : J'ai finalement obtenu de godoc os Wait, que Wait a changé en method of et j'ai réussi à faire :

   defer p.Wait(0)

J'ai finalement décidé de mettre

   defer p.Release()

au lieu de cela.

0voto

injartnak Points 1
package main

import (
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("cmd", "/C", "dir")
    output, err := cmd.Output()

    if err != nil {
        fmt.Println("Error executing command:", err)
        return
    }

    fmt.Println(string(output))
}

Utilisez la fonction exec.Command pour créer un nouveau processus cmd avec le drapeau /C et la commande dir comme argument. Capturez la sortie avec la méthode output() et imprimez-la.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X