如何在Go中使用我的系统命令shell?

时间:2015-01-16 23:32:47

标签: bash shell go interactive

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

1 个答案:

答案 0 :(得分:0)

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

的Gist中

这是一个很好的小演示,它使用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")
}