我正在使用这个包:os/exec http://golang.org/pkg/os/exec/来在操作系统中执行命令,但我似乎找不到获取退出代码的方法.我可以读取输出
即.
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() )
}
Run Code Online (Sandbox Code Playgroud)
tux*_*21b 78
很容易确定退出代码是否为0或其他内容.在第一种情况下,cmd.Wait()将返回nil(除非在设置管道时出现另一个错误).
不幸的是,在错误情况下,没有独立于平台的方法来获取退出代码.这也是它不属于API的原因.以下代码片段适用于Linux,但我没有在其他平台上测试过:
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", err)
}
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*vid 26
从golang版本1.12开始,退出代码可以以本机方式和跨平台方式使用。请参见ExitError和ExitCode()。
ExitCode返回已退出进程的退出代码;如果该进程尚未退出或被信号终止,则返回-1。
if err := cmd.Run() ; err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
return exitError.ExitCode()
}
}
Run Code Online (Sandbox Code Playgroud)
Reo*_*orx 20
这是我基于@ tux21b的答案的增强版本
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
}
Run Code Online (Sandbox Code Playgroud)
我已经在OSX上测试了它,如果它在其他平台上没有按预期工作,请告诉我,以便我们可以做得更好.
2019 年 9 月,Go 1.13引入了errors.As,它支持错误“解包”——便于在嵌套调用链中查找精确错误。
因此,要在运行外部命令时提取和检查两个最常见的错误:
err := cmd.Run()
var (
ee *exec.ExitError
pe *os.PathError
)
if errors.As(err, &ee) {
log.Println("exit code error:", ee.ExitCode()) // ran, but non-zero exit code
} else if errors.As(err, &pe) {
log.Printf("os.PathError: %v", pe) // "no such file ...", "permission denied" etc.
} else if err != nil {
log.Printf("general error: %v", err) // something really bad happened!
} else {
log.Println("success!") // ran without error (exit code zero)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
32287 次 |
| 最近记录: |