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