Exec a shell command in Go

﹥>﹥吖頭↗ 提交于 2019-11-27 18:08:50
jimt

This answer does not represent the current state of the Go standard library. Please take a look at @Lourenco's answer for an up-to-date method!


Your example does not actually read the data from stdout. This works for me.

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

The package "exec" was changed a little bit. The following code worked for me.

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

I hope this helps!

None of the provided answers allow to separate stdout and stderr so I try another answer.

First you get all the info you need, if you look at the documentation of the exec.Cmd type in the os/exec package. Look here: https://golang.org/pkg/os/exec/#Cmd

Especially the members Stdin and Stdout,Stderr where any io.Reader can be used to feed stdin of your newly created process and any io.Writer can be used to consume stdout and stderr of your command.

The function Shellout in the following programm will run your command and hand you its output and error output separatly as strings:

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)
}
qing
// 封装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

}
}

you may try this .

Here is a simple function that will run your command and capture the error, stdout, and stderr for you to inspect. You can easily see anything that might go wrong or be reported back to you.

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

You can use it like this (Converting a media file):

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

I've used this with Go 1.2-1.7

I did not get the Rosetta example to work in my Windows Go. Finally I managed to go past the old format of the Subprocess with this command to start outfile in notepad in windows. The wait constant parameter mentioned in one manual did not exist so I just left out Wait as the user will close the program by themself or leave it open to reuse.

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

You would change the os.Stdout.. to os.Pipe as previous answer

EDIT: I got it finally from godoc os Wait, that Wait has changed to method of and I succeeded to do:

   defer p.Wait(0)

Then I decided finally to put

   defer p.Release()

instead.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!