Выполнить команду оболочки в Go - PullRequest
35 голосов
/ 31 мая 2011

Я хочу выполнить команду оболочки в 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 может помочь в другом месте, но нет примера того, как это сделать. Есть идеи?

Ответы [ 6 ]

90 голосов
/ 17 октября 2011

Пакет "exec" был немного изменен .Следующий код работал для меня.

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

Надеюсь, это поможет!

5 голосов
/ 06 апреля 2017

Ни один из предоставленных ответов не позволяет разделить stdout и stderr, поэтому я пробую другой ответ.

Сначала вы получите всю необходимую информацию, если посмотрите документацию типа exec.Cmd в пакете os/exec. Смотрите здесь: https://golang.org/pkg/os/exec/#Cmd

Особенно члены Stdin и Stdout, Stderr, где любой io.Reader может использоваться для подачи stdin вашего недавно созданного процесса, а любой io.Writer может использоваться для потребления stdout и stderr вашей команды.

Функция 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)
}
2 голосов
/ 04 января 2015
// 封装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

}
}

Вы можете попробовать это.

0 голосов
/ 07 января 2017

Вот простая функция, которая запускает вашу команду и фиксирует ошибки, 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 голосов
/ 31 мая 2011

Я не получил пример Rosetta для работы в моем Windows Go. Наконец, мне удалось пройти старый формат подпроцесса с помощью этой команды, чтобы запустить outfile в блокноте в Windows. Указанный в одном руководстве параметр константы ожидания не существовал, поэтому я просто пропустил функцию Wait, поскольку пользователь сам закроет программу или оставит ее открытой для повторного использования.

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 Wait, что ожидание изменилось на метод, и мне удалось сделать:

   defer p.Wait(0)

Тогда я решил наконец поставить

   defer p.Release()

вместо.

0 голосов
/ 31 мая 2011

Этот ответ не отражает текущее состояние стандартной библиотеки Go.Пожалуйста, посмотрите на @ ответ Лоренцо , чтобы узнать, какой метод актуален!


Ваш пример фактически не считывает данные из 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()
}
...