【问题标题】:How do I use my system's command shell in Go? [duplicate]如何在 Go 中使用系统的命令 shell? [复制]
【发布时间】:2015-01-16 23:32:47
【问题描述】:

所以我想在 Go 中创建一个命令 shell。我的目标是在我正在考虑编写的便携式系统工具中使用它的功能。我认为一个很好的起点是可以演示运行系统命令的基础知识并允许用户与系统 shell 交互。

【问题讨论】:

    标签: bash shell go interactive


    【解决方案1】:

    我有这样的解决方案!实际上,我已将其发布在 Gist 中 gist.github.com/lee8oi/a8a90f559fe48355f800

    这是一个很好的小演示,它使用 Go 的 os/exec 包将输入/输出/错误直接通过管道传递到命令实例。当“bash”运行时,您将坐在一个非常简单的提示符下。您可以像使用 bash 一样与它进行交互(但仍然非常简化)。当您运行常规命令时,将显示输出,然后命令将退出(如“ping”)。我认为这将成为修补与 Go 中的系统 shell 交互方式的一个很好的起点。

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "log"
        "os"
        "os/exec"
        "sync"
    )
    
    func getPipes(c *exec.Cmd) (inp io.Writer, outp, errp io.Reader) {
        var err error
        if inp, err = c.StdinPipe(); err != nil {
            log.Fatal(err)
        }
        if outp, err = c.StdoutPipe(); err != nil {
            log.Fatal(err)
        }
        if errp, err = c.StderrPipe(); err != nil {
            log.Fatal(err)
        }
        return
    }
    
    func pipe(wg *sync.WaitGroup, inp io.Reader, outp io.Writer) {
        if wg != nil {
            defer wg.Done()
        }
        r := bufio.NewReader(inp)
        for {
            c, err := r.ReadByte()
            if err != nil {
                return
            }
            fmt.Fprintf(outp, "%s", string(c))
        }
    }
    
    func Command(args ...string) {
        var cmd *exec.Cmd
        var wg sync.WaitGroup
        if len(args) > 1 {
            cmd = exec.Command(args[0], args[1:]...)
        } else {
            cmd = exec.Command(args[0])
        }
        inp, outp, errp := getPipes(cmd)
        wg.Add(1)
        go pipe(&wg, errp, os.Stderr)
        wg.Add(1)
        go pipe(&wg, outp, os.Stdout)
        go pipe(nil, os.Stdin, inp)
        if err := cmd.Start(); err != nil {
            log.Fatal("start ", err)
        }
        wg.Wait()
    }
    
    func main() {
        Command("bash")
        Command("date")
        Command("echo", "some text")
        Command("ping", "-c 3", "www.google.com")
    }
    

    【讨论】:

    • 我想知道 Stack Overflow 问题/答案日期是否存在错误,或者您是否真的在不到一秒的时间内回答了自己。两者都在 23:32:47Z。
    • 给你的代码审查:如果你 ^D 退出 shell,这会给出一个 nil 指针异常。 interface {} 的使用很奇怪,只需使用io.Readerio.Writer。应该检查来自StdinPipe* 的错误,也应该检查来自Wait 的错误。 runPipe` 过于复杂 - 您可以将其全部替换为 io.Copy
    • 谢谢尼克。好东西。老实说,这只是一些用于在 Go 中玩 shell 的黑客代码。我确实检查了 Std{out,err,in}Pipe() 函数,它们只是从未触发过。但为了完整起见,我可以把它们放回去。考虑到您的建议,我将再次检查代码。再次感谢。到目前为止,你说的东西比整个 G+ Go 社区更有用。
    • 好的,我更新了代码。 Ctrl+D 不会再导致崩溃,添加了额外的错误检查,并用 io.Copy 替换了 bufio。如果您有任何其他建议,请继续随时用 em 打我 :)
    • 好的,io.Copy 方法随机给了我一些错误的文件描述符错误。事实证明我的做法更可靠。
    猜你喜欢
    • 2014-06-23
    • 2010-12-25
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 2013-04-04
    • 2013-06-19
    相关资源
    最近更新 更多