When unsure, I recommend looking at well known open source applications that have the functionality that you wish to make. As an example Air is a well known process spawner that monitors for file changes and restarts applications on change. They implement the start and kill process like this:
func (e *Engine) killCmd(cmd *exec.Cmd) (pid int, err error) {
pid = cmd.Process.Pid
// https://stackoverflow.com/a/44551450
kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(pid))
if e.config.Build.SendInterrupt {
if err = kill.Run(); err != nil {
return
}
time.Sleep(e.config.killDelay())
}
err = kill.Run()
// Wait releases any resources associated with the Process.
_, _ = cmd.Process.Wait()
return pid, err
}
func (e *Engine) startCmd(cmd string) (*exec.Cmd, io.ReadCloser, io.ReadCloser, error) {
var err error
if !strings.Contains(cmd, ".exe") {
e.runnerLog("CMD will not recognize non .exe file for execution, path: %s", cmd)
}
c := exec.Command("powershell", cmd)
stderr, err := c.StderrPipe()
if err != nil {
return nil, nil, nil, err
}
stdout, err := c.StdoutPipe()
if err != nil {
return nil, nil, nil, err
}
c.Stdout = os.Stdout
c.Stderr = os.Stderr
err = c.Start()
if err != nil {
return nil, nil, nil, err
}
return c, stdout, stderr, err
}
You can find the repo here
They also reference another stack overflow post as to why they use this specific method.