2012-04-30 17 views
33

Estoy usando el paquete: os/exec http://golang.org/pkg/os/exec/ para ejecutar un comando en el sistema operativo, pero parece que no encuentro la manera de obtener el código de salida. Puedo leer la salida aunqueObtener código de salida - Ir

es decir.

package main 

import(
    "os/exec" 
    "bytes" 
    "fmt" 
    "log" 
    ) 

func main() { 
    cmd := exec.Command("somecommand", "parameter") 
    var out bytes.Buffer 
    cmd.Stdout = &out 
    if err := cmd.Run() ; err != nil { 
     //log.Fatal(cmd.ProcessState.Success()) 
     log.Fatal(err) 
    } 
    fmt.Printf("%q\n", out.String()) 
} 

Respuesta

52

Es fácil determinar si el código de salida fue 0 o algo más. En el primer caso, cmd.Wait() devolverá cero (a menos que haya otro error al configurar las tuberías).

Desafortunadamente, no existe una forma independiente de plataforma para obtener el código de salida en el caso de error. Esa es también la razón por la cual no es parte de la API. El siguiente fragmento trabajará con Linux, pero no he probado en otras plataformas:

package main 

import "os/exec" 
import "log" 
import "syscall" 

func main() { 
    cmd := exec.Command("git", "blub") 

    if err := cmd.Start(); err != nil { 
     log.Fatalf("cmd.Start: %v") 
    } 

    if err := cmd.Wait(); err != nil { 
     if exiterr, ok := err.(*exec.ExitError); ok { 
      // The program has exited with an exit code != 0 

      // This works on both Unix and Windows. Although package 
      // syscall is generally platform dependent, WaitStatus is 
      // defined for both Unix and Windows and in both cases has 
      // an ExitStatus() method with the same signature. 
      if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 
       log.Printf("Exit Status: %d", status.ExitStatus()) 
      } 
     } else { 
      log.Fatalf("cmd.Wait: %v", err) 
     } 
    } 
} 

Sólo followtheapidocs para obtener más :)

+1

Miré en los documentos pero nunca encontré la manera de pasar de 'ProcessState' a' WaitStatus' ¿cómo hiciste eso ?. También acabo de encontrar en la lista de correo la solución (al igual que la que ha descrito) https://groups.google.com/forum/?fromgroups#!searchin/golang-nuts/exit$20code/golang- nuts/dKbL1oOiCIY/Bz_haQYmMrcJ Lo estoy intentando ahora en Windows y le hago saber :) – OscarRyz

+0

Definitivamente no es tan fácil obtener el código de salida, pero los documentos proporcionan al menos algunos consejos donde debe mirar a continuación. Pero no mencionan a Windows, así que espero su respuesta. – tux21b

+0

La lista de correo dice algo sobre Windows específico, pero acabo de ejecutar este código y funciona perfecto, esto está en go1. – OscarRyz

8

aquí está mi versión mejorada basada en tux21b @ ' s respuesta

utils/cmd.go

package utils 

import (
    "bytes" 
    "log" 
    "os/exec" 
    "syscall" 
) 

const defaultFailedCode = 1 

func RunCommand(name string, args ...string) (stdout string, stderr string, exitCode int) { 
    log.Println("run command:", name, args) 
    var outbuf, errbuf bytes.Buffer 
    cmd := exec.Command(name, args...) 
    cmd.Stdout = &outbuf 
    cmd.Stderr = &errbuf 

    err := cmd.Run() 
    stdout = outbuf.String() 
    stderr = errbuf.String() 

    if err != nil { 
     // try to get the exit code 
     if exitError, ok := err.(*exec.ExitError); ok { 
      ws := exitError.Sys().(syscall.WaitStatus) 
      exitCode = ws.ExitStatus() 
     } else { 
      // This will happen (in OSX) if `name` is not available in $PATH, 
      // in this situation, exit code could not be get, and stderr will be 
      // empty string very likely, so we use the default fail code, and format err 
      // to string and set to stderr 
      log.Printf("Could not get exit code for failed program: %v, %v", name, args) 
      exitCode = defaultFailedCode 
      if stderr == "" { 
       stderr = err.Error() 
      } 
     } 
    } else { 
     // success, exitCode should be 0 if go is ok 
     ws := cmd.ProcessState.Sys().(syscall.WaitStatus) 
     exitCode = ws.ExitStatus() 
    } 
    log.Printf("command result, stdout: %v, stderr: %v, exitCode: %v", stdout, stderr, exitCode) 
    return 
} 

he probado en OSX, si no funciona como se espera en otras plataformas, dígamelo para que podamos hacerlo mejor.

+0

Funciona en Ubuntu 16.04 Linux, y devuelve el stdout junto con el exitCode - justo lo que estaba buscando ... – MrMobileMan

+0

Me encanta esta función – n0nag0n

Cuestiones relacionadas