Подтвердить что ты не робот

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

4b9b3361

Ответ 1

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


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

Ответ 2

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

package main

import "os/exec"
import . "fmt"

func main() {
    app := "echo"

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

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

Ответ 3

Ни один из предоставленных ответов не позволяет разделить 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)
}

Ответ 4

// 封装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

}
}

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

Ответ 5

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

Ответ 6

Я не получил пример Rosetta для работы в Windows Go. Наконец, мне удалось пройти старый формат Subprocess с этой командой, чтобы запустить 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 как на предыдущий ответ

EDIT: я получил его, наконец, от godoc os Wait, что Wait изменился на метод, и мне это удалось:

   defer p.Wait(0)

Затем я решил, наконец, положить

   defer p.Release()

вместо.