A minimal Go package that separates command-line flags from positional arguments — no matter what order they appear in.
Go's standard flag package stops parsing flags as soon as it hits a positional argument. Run ./app task-1 -p and -p is ignored.
Libraries like pflag and Cobra solve this well, but they add configuration overhead that can feel heavy for small CLIs.
go-os-input-parser takes a simpler approach: scan raw os.Args, pull out the flags you define, write their values into variables you provide, and return whatever is left as clean positional input.
go get github.com/orashus/go-os-input-parser@latestpackage main
import (
"fmt"
"os"
input_parser "github.com/orashus/go-os-input-parser"
)
func main() {
var print, list bool
var name string
inputs := input_parser.ParseInput(
os.Args[1:],
[]input_parser.BoolTag{
{Short: "p", Long: "print", Container: &print},
{Short: "l", Long: "list", Container: &list},
},
[]input_parser.StringTag{
{Short: "n", Long: "name", Container: &name},
},
)
fmt.Println("inputs:", inputs)
fmt.Println("print:", print)
fmt.Println("list:", list)
fmt.Println("name:", name)
}| Type | Format | Example |
|---|---|---|
| Bool | -short or --long |
-p, --print |
| String | -short=value or --long=value |
-n="alice", --name=bob |
String values may be wrapped in double quotes; the quotes are stripped automatically.
Flags work the same regardless of position:
$ ./mycli task-1 task-2 -p
inputs: [task-1 task-2]
print: true
$ ./mycli -p task-1 task-2
inputs: [task-1 task-2]
print: true
$ ./mycli a b -n="alice"
inputs: [a b]
name: alice
$ ./mycli file.txt -v --out="result.txt" extra
inputs: [file.txt extra]
verbose: true
out: result.txtUse ParseInputWithHelp when you want -h / --help handled for you. Tag definitions include a Desc field used to print a usage screen, then the process exits with code 0.
inputs := input_parser.ParseInputWithHelp(
os.Args[1:],
[]input_parser.BoolTagWithDesc{
{Short: "p", Long: "print", Container: &print, Desc: "Print output"},
{Short: "l", Long: "list", Container: &list, Desc: "List items"},
},
[]input_parser.StringTagWithDesc{
{Short: "n", Long: "name", Container: &name, Desc: "Set the name"},
},
)Running ./mycli --help prints:
Usage: mycli [options] [arguments]
Options:
-h, --help Show this help message
-p, --print Print output
-l, --list List items
-n, --name= Set the name
func ParseInput(args []string, boolTags []BoolTag, stringTags []StringTag) []stringParses flags from args, writes values into the Container pointers on each tag, and returns the remaining positional arguments.
func ParseInputWithHelp(args []string, boolTags []BoolTagWithDesc, stringTags []StringTagWithDesc) []stringSame as ParseInput, but prints help and calls os.Exit(0) when -h or --help is present.
type BoolTag struct {
Short string
Long string
Container *bool
}
type StringTag struct {
Short string
Long string
Container *string
}
type BoolTagWithDesc struct {
Short string
Long string
Container *bool
Desc string
}
type StringTagWithDesc struct {
Short string
Long string
Container *string
Desc string
}ShortandLongare the flag names without the leading-or--.Containeris a pointer to the variable that receives the parsed value.Descis only used byParseInputWithHelpfor the help text.
- Order independent — flags can appear before, between, or after positional arguments
- Bool and string flags — presence flags and valued flags with
=syntax - Container pointers — parsed values are written directly into your variables
- Optional help — auto-generated usage text via
ParseInputWithHelp - Lightweight — a single focused API, no subcommand tree or config file
The package includes tests for bool tags, string tags, mixed arguments, empty input, and missing flags.
go test ./...
go test -v ./...