我正在寻找在Go中执行shell命令,并在程序中将结果输出作为字符串。我看到了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可以帮助其他地方,但没有如何这样做的例子。有什么想法吗?
答案 0 :(得分:87)
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))
}
我希望这有帮助!
答案 1 :(得分:5)
所提供的答案都不允许将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)
}
将运行您的命令并将其输出和错误输出分别作为字符串传递给您:
=INDEX(A2:A25,MATCH(TRUE,INDEX(SUBTOTAL(9,(OFFSET(C$2:C25,,,ROW(INDIRECT("1:25")),1)))>=2000,),0))-A2
答案 2 :(得分:2)
// 封装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
}
}
你可以试试这个。
答案 3 :(得分:0)
此答案不代表Go标准库的当前状态。请查看@Lourenco's answer了解最新方法!
您的示例实际上并未从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()
}
答案 4 :(得分:0)
这是一个简单的函数,它将运行您的命令并捕获错误,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
中使用了它答案 5 :(得分:0)
import (
"github.com/go-cmd/cmd"
)
const DefaultTimeoutTime = "1m"
func RunCMD(name string, args ...string) (err error, stdout, stderr []string) {
c := cmd.NewCmd(name, args...)
s := <-c.Start()
stdout = s.Stdout
stderr = s.Stderr
return
}
去测试
import (
"fmt"
"gotest.tools/assert"
"testing"
)
func TestRunCMD(t *testing.T) {
err, stdout, stderr := RunCMD("kubectl", "get", "pod", "--context", "cluster")
assert.Equal(t, nil, err)
for _, out := range stdout {
fmt.Println(out)
}
for _, err := range stderr {
fmt.Println(err)
}
}
答案 6 :(得分:-1)
我没有在我的Windows Go中使用Rosetta示例。最后,我设法使用此命令通过Subprocess的旧格式,在Windows中的记事本中启动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作为上一个答案
编辑:我终于从godoc os等了,等等已经改变了方法,我成功了: defer p.Wait(0)
然后我决定最终放
defer p.Release()
代替。