ctx, cancelCmd := context.WithCancel(context.Background())cmd := exec.CommandContext(ctx, cmdName, cmdArgs...)cmd.Stdin = stdinPipecmd.Stdout = stdoutPipecmd.Stderr = stderrPipeif err := cmd.Run(); err != nil {
g.log.Warnf("Run error: %w", err)
and that returns when the command exits, gets an (externally issued) SIGKILL, or gets a cancelCmd(). Every combination I've tried hangs because the pipes aren't closed. Although the pipes are monitored and drained (not shown), that doesn't help because the command doesn't get a chance to close them.}return nil
cmdName := "/bin/bash"cmdArgs := []string{
"-c","while true; do echo step; sleep 1; done",
}cmdStdinR, cmdStdinW := io.Pipe()cmdStdoutR, cmdStdoutW := io.Pipe()cmdStderrR, cmdStderrW := io.Pipe()
ctx, cancelCmd := context.WithCancel(context.Background())cmd := exec.CommandContext(ctx, cmdName, cmdArgs...)
cmd.Stdin = cmdStdinRcmd.Stdout = cmdStdoutWcmd.Stderr = cmdStderrW
if err := cmd.Start(); err != nil {
fmt.Println(err)
}
cmdStdinW.Close()
if err := cmd.Wait(); err != nil {
fmt.Println(err)
}
fmt.Println("DONE")cancelCmd = cancelCmdcmdStdoutR = cmdStdoutRcmdStderrR = cmdStderrR
cmdName := "/bin/bash"cmdArgs := []string{"-c", "while true; do echo step; sleep 1; done"}
cmdStdoutR, cmdStdoutW := io.Pipe()cmd := exec.Command(cmdName, cmdArgs...)cmd.Stdout = cmdStdoutWif err := cmd.Run(); err != nil {
fmt.Println(err)
}fmt.Println("DONE")cmdStdoutR = cmdStdoutR
On Jun 16, 2024, at 8:54 PM, Salvatore Domenick Desiano <near...@gmail.com> wrote:
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEQs7S-Gwuvh8MJ48Nv1Cwd7miHiUX4RdwKjqmeLqMBcWYYgJQ%40mail.gmail.com.
On Jun 16, 2024, at 9:33 PM, Robert Engels <ren...@ix.netcom.com> wrote:
I’m wondering if there’s a specific reason you’re using io.Pipe instead of the Cmd.StdoutPipe helper? When using io.Pipe you need to Close the pipe by yourself, but when using the Cmd.StdoutPipe, the Cmd.Wait will close the pipe for you.
Here’s a sample following your previous example:
func main() { defer err2.Catch() cmdName := "/bin/sh" cmdArgs := []string{ "-c", "for i in 1 2 3 4 5 6 7 8 9 10; do echo step $i; sleep 0.1; done", } cmd := exec.CommandContext(context.Background(), cmdName, cmdArgs...) stdoutPipe := try.To1(cmd.StdoutPipe()) var wg sync.WaitGroup go readPipe(stdoutPipe, &wg) try.To(cmd.Start()) wg.Wait() try.To(cmd.Wait()) fmt.Println("DONE") } func readPipe(src io.Reader, wg *sync.WaitGroup) { defer err2.Catch() wg.Add(1) defer wg.Done() buf := make([]byte, 256) for eof, n := try.IsEOF1(src.Read(buf)); !eof; eof, n = try.IsEOF1(src.Read(buf)) { try.To1(os.Stdout.Write(buf[:n])) } }And here’s a sample using io.Pipe; please see the noted line:
func main() { defer err2.Catch() cmdName := "/bin/sh" cmdArgs := []string{ "-c", "for i in 1 2 3 4 5 6 7 8 9 10; do echo step $i; sleep 0.1; done", } cmdStdoutR, cmdStdoutW := io.Pipe() cmd := exec.CommandContext(context.Background(), cmdName, cmdArgs...) cmd.Stdout = cmdStdoutW var wg sync.WaitGroup go readPipe(cmdStdoutR, &wg) try.To(cmd.Run()) cmdStdoutW.Close() // NOTE: needed for io.Pipe ↓ fmt.Println("DONE") wg.Wait() }To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/782a2013-703d-451c-9567-7be585d17c5fn%40googlegroups.com.