A flexible command execution wrapper with I/O redirection for Go. Execute external commands with full control over stdin, stdout, stderr, and process lifecycle.
- Synchronous and Asynchronous Execution - Run commands blocking or non-blocking
- Context Support - Cancel commands using Go contexts (Go 1.23+)
- I/O Redirection - Full control over stdin, stdout, and stderr
- Process Management - Signal handling, termination, and process information
- Thread-Safe - Safe for concurrent use with atomic operations
- Cross-Platform - Works on Linux and Darwin (macOS)
- Go 1.23 or higher
go get github.com/streamz/cmdiopackage main
import (
"context""fmt""os""os/user""time""github.com/streamz/cmdio"
)
funcmain() {
// Create options for command executionopts:=func() *cmdio.Options {
usr, _:=user.Current()
return&cmdio.Options{
In: os.Stdin,
Out: os.Stdout,
Err: os.Stderr,
Usr: usr,
}
}
// Synchronous executioncmd:=cmdio.New(opts)
info:=cmd.Run("ls", "-la")
fmt.Printf("Exit code: %d\n", info.Exit)
// Asynchronous executioncmd2:=cmdio.New(opts)
started, complete:=cmd2.Start("sleep", "5")
if<-started {
fmt.Println("Command started successfully")
info:=<-completefmt.Printf("Command finished: %+v\n", info)
}
// Context-based execution with timeoutctx, cancel:=context.WithTimeout(context.Background(), 2*time.Second)
defercancel()
cmd3:=cmdio.New(opts)
info=cmd3.RunContext(ctx, "sleep", "10")
ifinfo.Signaled {
fmt.Println("Command was terminated due to timeout")
}
}package main
import (
"bytes""fmt""os/user""github.com/streamz/cmdio"
)
funcmain() {
// Capture command outputvarstdout, stderr bytes.Bufferopts:=func() *cmdio.Options {
usr, _:=user.Current()
return&cmdio.Options{
In: nil,
Out: &stdout,
Err: &stderr,
Usr: usr,
}
}
cmd:=cmdio.New(opts)
info:=cmd.Run("echo", "Hello, World!")
fmt.Printf("Output: %s", stdout.String())
fmt.Printf("Errors: %s", stderr.String())
fmt.Printf("Exit code: %d\n", info.Exit)
}package main
import (
"time""os""os/user""github.com/streamz/cmdio"
)
funcmain() {
opts:=func() *cmdio.Options {
usr, _:=user.Current()
return&cmdio.Options{
In: os.Stdin,
Out: os.Stdout,
Err: os.Stderr,
Usr: usr,
}
}
cmd:=cmdio.New(opts)
started, complete:=cmd.Start("sleep", "60")
if<-started {
// Let it run for 2 secondstime.Sleep(2*time.Second)
// Terminate the commanderr:=cmd.Terminate()
iferr!=nil {
panic(err)
}
info:=<-completeifinfo.Signaled {
fmt.Println("Command was successfully terminated")
}
}
}Full API documentation is available at pkg.go.dev.
- Supports process group management
- Forwards signals to child processes
- Uses BSD-specific system calls for process enumeration
- Supports process death signal (Pdeathsig)
- Automatic cleanup when parent dies
Run tests with coverage:
go test -cover ./...Run benchmarks:
go test -bench=. -benchmem ./...Apache License 2.0 - See LICENSE file for details