Skip to content

Instantly share code, notes, and snippets.

@lee8oi
Last active January 9, 2025 15:31
Show Gist options
  • Save lee8oi/ec404fa99ea0f6efd9d1 to your computer and use it in GitHub Desktop.
Save lee8oi/ec404fa99ea0f6efd9d1 to your computer and use it in GitHub Desktop.
Using os.StartProcess() in Go for platform-independent system command execution.
package main
import (
"os"
"os/exec"
)
func Start(args ...string) (p *os.Process, err error) {
if args[0], err = exec.LookPath(args[0]); err == nil {
var procAttr os.ProcAttr
procAttr.Files = []*os.File{os.Stdin,
os.Stdout, os.Stderr}
p, err := os.StartProcess(args[0], args, &procAttr)
if err == nil {
return p, nil
}
}
return nil, err
}
func main() {
if proc, err := Start("ping", "-c 3", "www.google.com"); err == nil {
proc.Wait()
}
if proc, err := Start("zsh"); err == nil {
proc.Wait()
}
}
@jeffj1
Copy link

jeffj1 commented Oct 1, 2019

[Update] This bug will not occur, because line 18 will always return an err != nil, which is picked up by your main function.

Hello lee,

Thanks for this code, a good way to wrap around the low level os.Process* call.

There is a potential bug with the code however, in the event that exec.LookPath fails, the start function will return *os.Process = nil (line 18) , this will cause problems in your main function as a nil pointer dereference issue at proc.Wait, this should be removed.

Regards,
Jeff J

@coolaj86
Copy link

coolaj86 commented Oct 8, 2019

I just came across some code for this today... but I don't understand why would you use os.StartProcess instead of exec.Command. What's the advantage?

@lee8oi
Copy link
Author

lee8oi commented Oct 8, 2019 via email

@jeffj1
Copy link

jeffj1 commented Oct 9, 2019

I just came across some code for this today... but I don't understand why would you use os.StartProcess instead of exec.Command. What's the advantage?

* https://golang.org/pkg/os/exec/

os/Exec is a higher level implementation of the os.Process, with os.StartProcess, you can get the ProcessState with which you can get more control over the process than os/exec. For example, I had to run a commandline process which locks and when it crashes golang hangs until the lock is removed, but with processState.Release option I was able to release the process resources thereby allowing my code to run to completion. I could have used the os/exec.Start and os/exec.Wait() but it did not work for me.

@rsvix
Copy link

rsvix commented Sep 10, 2024

Hi, thank you for sharing.
Do you know how i can capture the output stream from the StartProcess command in realtime?

@lee8oi
Copy link
Author

lee8oi commented Sep 10, 2024 via email

@rsvix
Copy link

rsvix commented Sep 10, 2024

Thank you @lee8oi
I've tried using io pipes, MultiReader and bufio.NewScanner, but with no luck

For anyone reading, im trying to do something like this, but using os.StartProcess instead of exec.Command

multi := io.MultiReader(stdout, stderr)

if err := cmd.Start(); err != nil {
return err
}

in := bufio.NewScanner(multi)

for in.Scan() {
log.Printf(in.Text()) // write each line to the log or anything else
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment