Command Literals and Safety
On this page
The sh"…" literal builds a lazy Cmd; it does not start a shell or execute a
process. Call run() for a checked Result<Output, CmdError> or run_raw() if
a non-zero exit status is data rather than an error. These examples require the
local Zolo CLI, so the browser runner is disabled.
Builds a command, runs it, supplies standard input, and inspects an unchecked non-zero result.
// Feature: sh"…" command literals — Zolo as a typed Bash replacement.
// Syntax: `sh"git status {branch}"` builds a lazy `Cmd` (nothing runs);
// `.run()` executes and returns `Result<Output, CmdError>`.
// When to use: any place you'd reach for a shell script — with types,
// Result-based errors, and injection-safe interpolation for free.
// Lazy: building a command executes nothing.
let cmd = sh"git version"
print("built: {cmd}")
// .run() blocks and returns Result<Output, CmdError> — status ≠ 0 is Err.
match cmd.run() {
.Ok(out) => print("exit {out.status}: {out.stdout.trim()}"),
.Err(e) => print("failed [{e.status}]: {e.stderr}"),
}
// Chainable builders: cwd / env / stdin / timeout — each returns a new Cmd.
let hashed = sh"git hash-object --stdin".stdin("hello zolo").run()
match hashed {
.Ok(out) => print("hash: {out.stdout.trim()}"),
.Err(e) => print("failed: {e}"),
}
// .run_raw() never raises on status ≠ 0 — the `check=False` escape hatch.
let raw = sh"git definitely-not-a-subcommand".run_raw()
print("run_raw status (non-zero, no Err): {raw.status != 0}")
Requires the Zolo CLI/host — open in the playground or run locally.
Every interpolated value becomes one opaque argv entry. Arrays expand one
element at a time, and Raw is the explicit escape hatch for intentional
word-splitting.
Shows that hostile text and filenames containing spaces remain single arguments.
// Feature: safe interpolation — the shell-injection class, deleted.
// Syntax: every `{expr}` in sh"…" becomes ONE opaque argv word, never
// re-interpreted by a shell (there is no shell: argv goes straight to the
// OS). `Raw(text)` is the explicit opt-out; arrays splice element-wise.
// When to use: always — it's the default. Compare with the legacy
// `os.execute("cat " + filename)`, where concatenation IS the bug.
// A hostile value stays ONE argument — argv inspection proves it:
let evil = "; rm -rf ~ --oops"
let c = sh"cat {evil}"
let argv = c.__stages[0].argv
print("argv len (cat + 1 opaque arg): {argv.len()}")
print("the whole payload is one word: {argv[1]}")
// Values glue to adjacent literal text and still form one word:
let rev = "deadbeef"
let tagged = sh"docker build -t app:{rev} ."
print("glued word: {tagged.__stages[0].argv[3]}")
// Arrays splice as separate arguments (element boundaries, not spaces):
let files = ["a.txt", "name with spaces.txt"]
let tar = sh"tar -cf out.tar {files}"
print("spaced filename survives as one word: {tar.__stages[0].argv[4]}")
// Raw() — the author takes responsibility; text is word-split like source:
let flags = Raw("-la --color=auto")
let ls = sh"ls {flags}"
print("raw splice words: {ls.__stages[0].argv.len() - 1}")
Requires the Zolo CLI/host — open in the playground or run locally.
run() uses the ordinary Result type, so multi-step scripts can propagate
the first CmdError with ?.
Propagates command failures and distinguishes a missing executable with status
-1.
// Feature: Cmd.run() → Result<Output, CmdError> — errors you can type.
// Syntax: status ≠ 0 is already Err; `?` propagates it like any Result.
// Launch failure (missing binary) and timeout use status -1.
// When to use: multi-step scripts where Bash would scatter `$?` checks.
fn describe() -> Result<str, CmdError> {
// Each step propagates with `?` — first failure short-circuits.
// (Bind before the field access: `run()?.stdout` would lex as the
// `?.` optional-chain operator, which is a different thing.)
let v = sh"git version".run()?
let version = v.stdout.trim()
let h = sh"git hash-object --stdin".stdin(version).run()?
return Result.Ok("{version} -> {h.stdout.trim()}")
}
match describe() {
Result::Ok(line) => print(line),
Result::Err(e) => print("step failed [{e.status}]: {e.stderr}"),
}
// Missing binary → Err with status -1 (never a shell "command not found"):
match sh"zolo-example-missing-binary".run() {
Result::Ok(_) => print("unexpected"),
Result::Err(e) => print("launch failure status: {e.status}"),
}
Requires the Zolo CLI/host — open in the playground or run locally.
See also