package main import ( "bufio" "context" "fmt" "io" "os/exec" "sync" "time" ) func main() { //ctx, cancel := context.WithCancel(context.Background()) //go func(cancelFunc context.CancelFunc) { // time.Sleep(10 * time.Second) // cancelFunc() //}(cancel) //err := Command(ctx, "ping www.baidu.com") //if err != nil { // return //} //err := RunWithTimeout(10*time.Second, "ping www.baidu.com") //if err != nil { // return //} err := RunCmd("ping www.baidu.com") if err != nil { return } } func RunWithTimeout(timeout time.Duration, cmd string) error { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() return Command(ctx, cmd) } func RunCmd(cmd string) error { return Command(context.Background(), cmd) } func Command(ctx context.Context, cmd string) error { // c := exec.CommandContext(ctx, "cmd", "/C", cmd) c := exec.CommandContext(ctx, "bash", "-c", cmd) // mac linux stdout, err := c.StdoutPipe() if err != nil { return err } var wg sync.WaitGroup wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() reader := bufio.NewReader(stdout) for { // 其实这段去掉程序也会正常运行,只是我们就不知道到底什么时候Command被停止了,而且如果我们需要实时给web端展示输出的话,这里可以作为依据 取消展示 select { // 检测到ctx.Done()之后停止读取 case <-ctx.Done(): if ctx.Err() != nil { fmt.Printf("程序出现错误: %q", ctx.Err()) } else { fmt.Println("程序被终止") } return default: readString, err := reader.ReadString('\n') if err != nil || err == io.EOF { return } fmt.Print(readString) } } }(&wg) err = c.Start() wg.Wait() return err }