在Go中执行shell命令

时间:2011-05-31 02:18:08

标签: go shellexecute

我正在寻找在Go中执行shell命令,并在程序中将结果输出作为字符串。我看到了Rosetta Code版本:

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

但是这并没有以我可以以编程方式访问的方式捕获实际标准或错误 - 那些仍然打印到常规stdout / stderr。我看到使用Pipe作为out或err可以帮助其他地方,但没有如何这样做的例子。有什么想法吗?

7 个答案:

答案 0 :(得分:87)

包“exec”有点changed。以下code为我工作。

package main

import "os/exec"

func main() {
    app := "echo"
    //app := "buah"

    arg0 := "-e"
    arg1 := "Hello world"
    arg2 := "\n\tfrom"
    arg3 := "golang"

    cmd := exec.Command(app, arg0, arg1, arg2, arg3)
    stdout, err := cmd.Output()

    if err != nil {
        println(err.Error())
        return
    }

    print(string(stdout))
}

我希望这有帮助!

答案 1 :(得分:5)

所提供的答案都不允许将stdoutstderr分开,所以我尝试了另一个答案。

如果您查看exec.Cmd包中os/exec类型的文档,首先获得所需的所有信息。看这里:https://golang.org/pkg/os/exec/#Cmd

特别是成员StdinStdoutStderr,其中任何io.Reader都可用于为新创建的流程stdin提供io.Writer stdout可用于使用命令的stderrShellout

以下程序中的函数package main import ( "bytes" "fmt" "log" "os/exec" ) const ShellToUse = "bash" func Shellout(command string) (error, string, string) { var stdout bytes.Buffer var stderr bytes.Buffer cmd := exec.Command(ShellToUse, "-c", command) cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() return err, stdout.String(), stderr.String() } func main() { err, out, errout := Shellout("ls -ltr") if err != nil { log.Printf("error: %v\n", err) } fmt.Println("--- stdout ---") fmt.Println(out) fmt.Println("--- stderr ---") fmt.Println(errout) } 将运行您的命令并将其输出和错误输出分别作为字符串传递给您:

=INDEX(A2:A25,MATCH(TRUE,INDEX(SUBTOTAL(9,(OFFSET(C$2:C25,,,ROW(INDIRECT("1:25")),1)))>=2000,),0))-A2

答案 2 :(得分:2)

// 封装exec ,有shell= true 这样的选项

func Cmd(cmd string, shell bool) []byte {

if shell {
    out, err := exec.Command("bash", "-c", cmd).Output()
    if err != nil {
        panic("some error found")
    }
    return out
} else {
    out, err := exec.Command(cmd).Output()
    if err != nil {
        panic("some error found")
    }
    return out

}
}
你可以试试这个。

答案 3 :(得分:0)

此答案不代表Go标准库的当前状态。请查看@Lourenco's answer了解最新方法!


您的示例实际上并未从stdout读取数据。这对我有用。

package main

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

func main() {
    app := "/bin/ls"
    cmd, err := exec.Run(app, []string{app, "-l"}, nil, "", exec.DevNull, exec.Pipe, exec.Pipe)

    if (err != nil) {
       fmt.Fprintln(os.Stderr, err.String())
       return
    }

    var b bytes.Buffer
    io.Copy(&b, cmd.Stdout)
    fmt.Println(b.String())

    cmd.Close()
}

答案 4 :(得分:0)

这是一个简单的函数,它将运行您的命令并捕获错误,stdout和stderr供您检查。您可以轻松查看可能出错的任何内容或向您报告。

// RunCMD is a simple wrapper around terminal commands
func RunCMD(path string, args []string, debug bool) (out string, err error) {

    cmd := exec.Command(path, args...)

    var b []byte
    b, err = cmd.CombinedOutput()
    out = string(b)

    if debug {
        fmt.Println(strings.Join(cmd.Args[:], " "))

        if err != nil {
            fmt.Println("RunCMD ERROR")
            fmt.Println(out)
        }
    }

    return
}

您可以像这样使用它(转换媒体文件):

args := []string{"-y", "-i", "movie.mp4", "movie_audio.mp3", "INVALID-ARG!"}
output, err := RunCMD("ffmpeg", args, true)

if err != nil {
    fmt.Println("Error:", output)
} else {
    fmt.Println("Result:", output)
}

我在Go 1.2-1.7

中使用了它

答案 5 :(得分:0)


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
}

去测试

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

答案 6 :(得分:-1)

我没有在我的Windows Go中使用Rosetta示例。最后,我设法使用此命令通过Subprocess的旧格式,在Windows中的记事本中启动outfile。一个手册中提到的等待常数参数不存在,所以我只是省略了等待,因为用户将自己关闭程序或保持打开以重复使用。

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

您可以将os.Stdout ..更改为os.Pipe作为上一个答案

编辑:我终于从godoc os等了,等等已经改变了方法,我成功了:

   defer p.Wait(0)

然后我决定最终放

   defer p.Release()

代替。