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