package utils import ( "bufio" "bytes" "errors" "fmt" "io" "os" "os/exec" "time" ) func ShellExecute(dir, exe string, args ...string) (string, error) { cmd := exec.Command(exe, args...) stdout, err := cmd.StdoutPipe(); if nil != err { msg := fmt.Sprintf("ShellExecute cmd.StdoutPipe err:%v", err) return "", errors.New(msg) } cmd.Stderr = os.Stderr if "" != dir { cmd.Dir = dir } err = cmd.Start() if nil != err { msg := fmt.Sprintf("ShellExecute cmd.Start err:%v", err) return "", errors.New(msg) } var buffer bytes.Buffer reader := bufio.NewReader(stdout) for { line, err2 := reader.ReadString('\n') if io.EOF == err2 { break } if nil != err2 { msg := fmt.Sprintf("ShellExecute reader.ReadString err:%v", err2) return "", errors.New(msg) } buffer.WriteString(line) } err = cmd.Wait() if nil != err { msg := fmt.Sprintf("ShellExecute cmd.Wait err:%v", err) return "", errors.New(msg) } return buffer.String(), nil } type TerminateFunc func(string) string func ShellExecuteEx(d time.Duration, t TerminateFunc, dir, exe string, args ...string) (string, error) { cmd := exec.Command(exe, args...) stdout, err := cmd.StdoutPipe(); if nil != err { msg := fmt.Sprintf("ShellExecuteEx cmd.StdoutPipe err:%v", err) return "", errors.New(msg) } cmd.Stderr = os.Stderr if "" != dir { cmd.Dir = dir } err = cmd.Start() if nil != err { msg := fmt.Sprintf("ShellExecuteEx cmd.Start err:%v", err) return "", errors.New(msg) } ch := make(chan string) go func(out io.ReadCloser, command *exec.Cmd) { reader := bufio.NewReader(out) for { line, err2 := reader.ReadString('\n') if io.EOF == err2 { ch <- "" break } if nil != err2 { break } address := t(line) if len(address) > 0 { err := cmd.Process.Signal(os.Kill) if nil != err { fmt.Println("failed to send signal to child process", err) } ch <- address break } } }(stdout, cmd) var address string select { case address = <-ch: err = nil break case <-time.After(d): _ = cmd.Process.Signal(os.Kill) err = errors.New("Timeout error") break } _ = cmd.Wait() return address, err }