This question already has an answer here:
So I would like to create a command shell in Go. My goal is to use its capabilities in portable system tools I'm thinking about writing. I think a great starting point would be something that can demonstrate the basics of running system commands and allowing the user to interact with the system shell.
</div>
I have such a solution! I actually have it posted in a Gist at gist.github.com/lee8oi/a8a90f559fe48355f800
Its a nice little demonstration that uses Go's os/exec package to directly pipe input/output/error to the command instance. When "bash" runs you'll be sitting at a very simple prompt. You can interact with it much like you would with bash (but still pretty simplified). When you run a regular command the output will be displayed then the command will exit (like with "ping"). I think this would make a great starting point for tinkering with ways to interact with the system shell in Go.
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")
}