go-shellwords

A Go library that splits shell-style command-line strings into argument slices, honoring POSIX quoting, escaping, and substitution rules.

Library
Go
vv1.0.14
576stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
62/100Good
Development Activity60
Maintenance44
Community64
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture62
Code Quality78
Innovation58
Learning Curve80

go-shellwords gives Go programs a small, dependency-free way to take a raw command-line string — the kind a user might type into a shell, or that arrives from a config file, SSH session, or subprocess wrapper — and split it into the argument slice a shell would produce. It implements POSIX-style word splitting: single and double quotes, backslash escaping, environment variable expansion ($FOO and ${FOO}), and optional backtick or $() command substitution, each of which can be toggled independently on the Parser struct.

The library exposes both a package-level Parse/ParseWithEnvs convenience API and a stateful Parser type for callers who need custom separators, a working directory for command substitution, or a custom Getenv function instead of os.Getenv. Recent versions add hardening against a class of security issues around unmatched parentheses in command substitution, addressed with explicit error returns rather than silently executing partial input.

What You Get

  • Parse(line string) - a package-level function that tokenizes a command line into []string using default parser settings.
  • Parser struct - a stateful parser exposing ParseEnv, ParseBacktick, ParseComment, a custom Getenv, and a Dir for command substitution.
  • ParseWithEnvs - splits leading KEY=VALUE environment assignments from the actual command arguments, mirroring how a shell treats FOO=bar cmd args.
  • SetExcludeSeparators - lets callers mark specific characters (e.g. ;, \t) as non-separators for line-oriented parsing use cases.
  • Position tracking - after a Parse call, Parser.Position reports where an unconsumed separator (like ; or &&) was found, so callers can resume parsing the remainder of a multi-command line.

Common Use Cases

  • Building a REPL or shell-like CLI - tokenizing typed-in commands the same way a real shell would before dispatching to exec.Command.
  • Parsing user-supplied command templates - splitting a stored string like ffmpeg -i "input file.mp4" -y out.mp4 from a config or database field into a safe argv slice.
  • Re-implementing shell semantics in Go tools - task runners and automation tools that accept a single “command” string field and need to split it correctly, quotes and all.
  • Environment-aware command construction - expanding $VAR/${VAR} references inside a stored command string before executing it, without invoking a real shell.

Under The Hood

Architecture The library is a flat, single-package implementation with no internal layering: shellwords.go holds the whole tokenizer as one large character-by-character state machine (Parser.Parse), tracking quote state (single/double), backtick/$() command-substitution state, escape state, and comment state via a handful of booleans, with platform-specific command execution split into util_posix.go and util_windows.go behind a shellRun function selected by build tags. There is no dependency injection or plugin surface; the only extension points are the public fields on Parser (ParseEnv, ParseBacktick, ParseComment, Getenv, Dir, excluded separators). Because the whole state machine lives in one function, changing tokenization behavior (e.g. adding a new quote style) means editing the central Parse loop directly rather than composing new behavior externally.

Tech Stack The module (github.com/mattn/go-shellwords, Go 1.13) has zero third-party dependencies — it uses only the Go standard library (bytes, errors, os, os/exec, strings, unicode). Command substitution (backtick/$()) shells out via os/exec.Command, invoking $SHELL (or /bin/sh as a fallback) on POSIX and an equivalent path on Windows. There is no build system beyond go build/go test; CI is driven by a Travis config and a go.test.sh coverage script, with codecov integration referenced in the README badges.

Code Quality Testing is thorough for a library this size: shellwords_test.go covers dozens of table-driven cases for quoting, escaping, environment expansion, comments, backtick/$() substitution, and error paths, and shellwords_security_test.go adds targeted regression tests for a fixed vulnerability class around unmatched closing parentheses in command substitution (previously a code-execution-adjacent risk when ParseBacktick was enabled on untrusted input). Error handling is explicit — the parser returns a plain errInvalidCmdLine sentinel error rather than panicking on malformed quoting or substitution syntax. Naming is idiomatic Go; there are no generic type parameters or heavy abstractions to assess for type safety. No linter or formatter config (e.g. .golangci.yml) is present in the repo, and CI is limited to Travis rather than GitHub Actions.

API Design What distinguishes go-shellwords from a naive whitespace split is that it implements a meaningful subset of actual POSIX shell tokenization semantics — nested quoting, backslash escapes inside and outside quotes, environment variable expansion with ${VAR} brace syntax, and optional shell-out command substitution — while remaining a small, auditable, dependency-free codebase. The project’s own security test suite (added specifically to reject unmatched ) characters rather than executing arbitrary shell fragments) shows a deliberate hardening pass around the most dangerous feature (ParseBacktick/command substitution), which is opt-in rather than the default — a meaningful safety design choice for a library commonly used to parse externally-supplied strings.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search