在GO中执行外壳命令

发布于 2025-01-23 06:08:09 字数 536 浏览 3 评论 0原文

我希望在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。我看到使用管道作为外出或ERR可以在其他地方有所帮助,但没有这样做的例子。有什么想法吗?

I'm looking to execute a shell command in Go and get the resulting output as a string in my program. I saw the Rosetta Code version:

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

But this doesn't capture the actual standard out or err in a way that I can programatically access - those still print out to the regular stdout / stderr. I saw that using Pipe as the out or err could help elsewhere, but no example of how to do so. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

不一样的天空 2025-01-30 06:08:09

软件包“ exec”为更改了 有点一点。以下代码对我有用。

package main

import (
    "fmt"
    "os/exec"
)

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 {
        fmt.Println(err.Error())
        return
    }

    // Print the output
    fmt.Println(string(stdout))
}

The package "exec" was changed a little bit. The following code worked for me.

package main

import (
    "fmt"
    "os/exec"
)

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 {
        fmt.Println(err.Error())
        return
    }

    // Print the output
    fmt.Println(string(stdout))
}
空气里的味道 2025-01-30 06:08:09

提供的答案都没有允许分开stdoutstderr,因此我尝试了另一个答案。

首先,如果您查看exec.cmdos/exec/exec软件包中键入exec.cmd的文档。在这里查看: https://golang.org/pkg/pkg/os/exec/exec/exec/qun.cmd

尤其是成员stdinstdoutstderr,其中任何io.reader可用于喂食您新创建的过程的stdin可以使用任何io.writer用于消费命令的stdout stder> stderr 。

函数shellOut在以下程序中将运行您的命令,并将其输出和错误输出分别为字符串。

由于参数值被执行为shell命令,请进行消毒
参数构建中使用的所有外部输入
价值。

可能不会在生产中以这种形式使用它。

package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
)

const ShellToUse = "bash"

func Shellout(command string) (string, string, error) {
    var stdout bytes.Buffer
    var stderr bytes.Buffer
    cmd := exec.Command(ShellToUse, "-c", command)
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr
    err := cmd.Run()
    return stdout.String(), stderr.String(), err
}

func main() {
    out, errout, err := Shellout("ls -ltr")
    if err != nil {
        log.Printf("error: %v\n", err)
    }
    fmt.Println("--- stdout ---")
    fmt.Println(out)
    fmt.Println("--- stderr ---")
    fmt.Println(errout)
}

None of the provided answers allow to separate stdout and stderr so I try another answer.

First you get all the info you need, if you look at the documentation of the exec.Cmd type in the os/exec package. Look here: https://golang.org/pkg/os/exec/#Cmd

Especially the members Stdin and Stdout,Stderr where any io.Reader can be used to feed stdin of your newly created process and any io.Writer can be used to consume stdout and stderr of your command.

The function Shellout in the following programm will run your command and hand you its output and error output separatly as strings.

As the parameter value is executed as a shell command, sanitize
all external inputs used in the construction of the parameter
value.

Probably don't use it in this form in production.

package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
)

const ShellToUse = "bash"

func Shellout(command string) (string, string, error) {
    var stdout bytes.Buffer
    var stderr bytes.Buffer
    cmd := exec.Command(ShellToUse, "-c", command)
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr
    err := cmd.Run()
    return stdout.String(), stderr.String(), err
}

func main() {
    out, errout, err := Shellout("ls -ltr")
    if err != nil {
        log.Printf("error: %v\n", err)
    }
    fmt.Println("--- stdout ---")
    fmt.Println(out)
    fmt.Println("--- stderr ---")
    fmt.Println(errout)
}
夜还是长夜 2025-01-30 06:08:09

此答案不代表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()
}

This answer does not represent the current state of the Go standard library. Please take a look at @Lourenco's answer for an up-to-date method!


Your example does not actually read the data from stdout. This works for me.

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()
}
亽野灬性zι浪 2025-01-30 06:08:09
// Wrap exec, with option to use bash shell

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

您可以尝试一下。

// Wrap exec, with option to use bash shell

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

you may try this .

风吹短裙飘 2025-01-30 06:08:09
package main

import (
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("cmd", "/C", "dir")
    output, err := cmd.Output()

    if err != nil {
        fmt.Println("Error executing command:", err)
        return
    }

    fmt.Println(string(output))
}

使用exec. -command函数用 /c flag和dir命令创建一个新的CMD进程作为参数
使用()方法捕获输出并打印。

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("cmd", "/C", "dir")
    output, err := cmd.Output()

    if err != nil {
        fmt.Println("Error executing command:", err)
        return
    }

    fmt.Println(string(output))
}

Use the exec.Command function to create a new cmd process with the /C flag and the dir command as its argument
Capture output with output() method and print it.

緦唸λ蓇 2025-01-30 06:08:09

这是一个简单的功能,它将运行您的命令并捕获错误,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一起使用

Here is a simple function that will run your command and capture the error, stdout, and stderr for you to inspect. You can easily see anything that might go wrong or be reported back to you.

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

You can use it like this (Converting a media file):

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

I've used this with Go 1.2-1.7

毅然前行 2025-01-30 06:08:09

如果要在执行进度的情况下运行长期运行的脚本异步,则可以使用io.multiwriter捕获命令输出,然后将其转发到stdout/stderr

import (
    "fmt"
    "io"
    "os"
    "os/exec"
)

var stdoutBuf, stderrBuf bytes.Buffer

cmd := exec.Command("/some-command")

cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)

err := cmd.Start()  // Starts command asynchronously

if err != nil {
    fmt.Printf(err.Error())
}

If you want run long-running script asynchronously with execution progress, you may capture command output using io.MultiWriter and forward it to stdout/stderr:

import (
    "fmt"
    "io"
    "os"
    "os/exec"
)

var stdoutBuf, stderrBuf bytes.Buffer

cmd := exec.Command("/some-command")

cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)

err := cmd.Start()  // Starts command asynchronously

if err != nil {
    fmt.Printf(err.Error())
}
风向决定发型 2025-01-30 06:08:09

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


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
}

go test

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

絕版丫頭 2025-01-30 06:08:09

我没有在窗户上有Rosetta示例来工作。最后,我设法通过此命令超过了子过程的旧格式,以在Windows的Notepad中启动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()

I did not get the Rosetta example to work in my Windows Go. Finally I managed to go past the old format of the Subprocess with this command to start outfile in notepad in windows. The wait constant parameter mentioned in one manual did not exist so I just left out Wait as the user will close the program by themself or leave it open to reuse.

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

You would change the os.Stdout.. to os.Pipe as previous answer

EDIT: I got it finally from godoc os Wait, that Wait has changed to method of and I succeeded to do:

   defer p.Wait(0)

Then I decided finally to put

   defer p.Release()

instead.

音盲 2025-01-30 06:08:09

我最终这样做是为了获得退出错误代码,命令输出和错误:

parts := strings.Split("netstat -tupln", " ")
cmd := exec.Command(parts[0], parts[1:]...)
out, err := cmd.Output()
exitCode := cmd.ProcessState.ExitCode()

在上面答案的帮助下(以及stackoverflow上的其他问题),希望这对某人有所帮助。

I ended up doing this to get exit error code, command output and error:

parts := strings.Split("netstat -tupln", " ")
cmd := exec.Command(parts[0], parts[1:]...)
out, err := cmd.Output()
exitCode := cmd.ProcessState.ExitCode()

with the help from answers above (and other questions on stackoverflow), hope this helps someone.

也只是曾经 2025-01-30 06:08:09

Here's a great alternative using the cmdx library that makes executing commands and capturing output simpler and more intuitive:

package main

import (
    "github.com/kgs19/cmdx"
    "log"
)

func main() {
    command := "date"
    args := []string{"+%H:%M"}
    out, err := cmdx.RunCommandReturnOutput(command, args...)
    if err != nil {
        log.Fatalf("Error executing 'date' command: %v", err)
    }
    println("cmd output: " + out)
}

Explanation

  • <代码> cmdx.runco​​mmandReturnOutput(命令,args ...):此函数运行具有给定参数的指定命令,并将输出返回为字符串。

有关更多信息,请查看 github存储库

Here's a great alternative using the cmdx library that makes executing commands and capturing output simpler and more intuitive:

package main

import (
    "github.com/kgs19/cmdx"
    "log"
)

func main() {
    command := "date"
    args := []string{"+%H:%M"}
    out, err := cmdx.RunCommandReturnOutput(command, args...)
    if err != nil {
        log.Fatalf("Error executing 'date' command: %v", err)
    }
    println("cmd output: " + out)
}

Explanation

  • cmdx.RunCommandReturnOutput(command, args...): This function runs the specified command with the given arguments and returns the output as a string.

For more information, check out the GitHub repository.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文