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"
)
func main() {
// Create options for command execution
opts := func() *cmdio.Options {
usr, _ := user.Current()
return &cmdio.Options{
In: os.Stdin,
Out: os.Stdout,
Err: os.Stderr,
Usr: usr,
}
}
// Synchronous execution
cmd := cmdio.New(opts)
info := cmd.Run("ls", "-la")
fmt.Printf("Exit code: %d\n", info.Exit)
// Asynchronous execution
cmd2 := cmdio.New(opts)
started, complete := cmd2.Start("sleep", "5")
if <-started {
fmt.Println("Command started successfully")
info := <-complete
fmt.Printf("Command finished: %+v\n", info)
}
// Context-based execution with timeout
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
cmd3 := cmdio.New(opts)
info = cmd3.RunContext(ctx, "sleep", "10")
if info.Signaled {
fmt.Println("Command was terminated due to timeout")
}
}package main
import (
"bytes"
"fmt"
"os/user"
"github.com/streamz/cmdio"
)
func main() {
// Capture command output
var stdout, stderr bytes.Buffer
opts := 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"
)
func main() {
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 seconds
time.Sleep(2 * time.Second)
// Terminate the command
err := cmd.Terminate()
if err != nil {
panic(err)
}
info := <-complete
if info.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