web-dev-qa-db-ja.com

Goでシェルコマンドを実行する

Goでシェルコマンドを実行し、プログラムで文字列として結果の出力を取得しようとしています。 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として使用すると他の場所で役立つことがわかりましたが、その方法の例はありません。何か案は?

35
Chris Bunch

この回答は、Go標準ライブラリの現在の状態を表すものではありません。最新の方法については、 @ Lourenco's answer をご覧ください!


あなたの例は、実際には標準出力からデータを読み取りません。これは私のために働く。

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()
}
0
jimt

パッケージ「exec」は 変更済み 少しでした。次の 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))
}

これがお役に立てば幸いです!

92
Lourenco

提供された回答ではstdoutstderrを分離することはできないため、別の回答を試みます。

exec.Cmdパッケージのos/execタイプのドキュメントを見ると、まず必要な情報をすべて入手できます。ここを見てください: https://golang.org/pkg/os/exec/#Cmd

特に、メンバーStdinおよびStdoutStderrでは、io.Readerを使用して、新しく作成されたプロセスのstdinio.Writerは、コマンドのstdoutstderrを使用するために使用できます。

次のプログラムのShellout関数はコマンドを実行し、その出力とエラー出力を文字列として分離して渡します。

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

}
}

これを試すことができます。

2
qing

コマンドを実行し、エラー、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でこれを使用しました

0
Xeoncross