POSIX-like shell word splitting, escaping, and joining.
Inspired by Python's shlex (split/quote/join) and Ruby's
Shellwords, with an Elixir-native API:
split/2/split!/2— parse a shell-like command string into wordsescape/1— make one argument safe as a single shell wordjoin/1— escape and join argv into one shell-safe string
Examples
iex> ShellWords.split(~S(cp "my file.txt" /tmp))
{:ok, ["cp", "my file.txt", "/tmp"]}
iex> ShellWords.join(["git", "commit", "-m", "initial commit"])
"git commit -m 'initial commit'"Scope
This is not a shell interpreter. There is no command execution, pipe or
redirect handling, variable expansion, command substitution, globbing,
tilde expansion, or comment parsing. # is an ordinary character.
Only POSIX-like shells are targeted; there is no Windows cmd.exe or
PowerShell escaping.
Security
Prefer argv-based command execution when possible:
System.cmd("echo", ["hello world"])Use escape/1 or join/1 only when you must build a shell command
string. The core guarantee, verified by property-based tests, is the
round trip:
ShellWords.split(ShellWords.join(argv)) == {:ok, argv}for every list of valid UTF-8 strings.
Details
Word separators are exactly ASCII space, tab, newline, and carriage return; Unicode whitespace is an ordinary character. Backslash-newline is not line continuation: the newline is kept as a literal character. Error positions are 0-based byte offsets. Behavior on invalid UTF-8 input is unspecified and may change.
Summary
Functions
Escapes a string so a POSIX shell parses it back as a single word with the original content.
Escapes each argument with escape/1 and joins them with single spaces,
producing one shell-safe command string.
Splits a shell-like command string into a list of words.
Like split/2, but returns the word list directly and raises
ShellWords.ParseError on parse errors.
Functions
Escapes a string so a POSIX shell parses it back as a single word with the original content.
Returns the string unchanged only when it is non-empty and consists solely
of unambiguously safe ASCII characters; otherwise wraps it in single quotes,
escaping embedded single quotes. The empty string becomes "''".
Output style matches Python's shlex.quote (single-quote wrapping), not
Ruby's backslash-style Shellwords.escape.
Examples
iex> ShellWords.escape("hello")
"hello"
iex> ShellWords.escape("hello world")
"'hello world'"
iex> ShellWords.escape("")
"''"
Escapes each argument with escape/1 and joins them with single spaces,
producing one shell-safe command string.
Examples
iex> ShellWords.join(["echo", "hello world"])
"echo 'hello world'"
iex> ShellWords.join([])
""
@spec split( String.t(), keyword() ) :: {:ok, [String.t()]} | {:error, ShellWords.ParseError.t()}
Splits a shell-like command string into a list of words.
Returns {:ok, words} or {:error, %ShellWords.ParseError{}}.
No options are supported yet; the opts argument exists to keep the arity
stable for future releases. Unknown options raise ArgumentError.
Examples
iex> ShellWords.split("ls -la /tmp")
{:ok, ["ls", "-la", "/tmp"]}
iex> ShellWords.split("")
{:ok, []}
Like split/2, but returns the word list directly and raises
ShellWords.ParseError on parse errors.
Examples
iex> ShellWords.split!(~S(echo "hello world"))
["echo", "hello world"]