Utility: run - execute a script of commands
Status: Built + QEMU-verified (osdev test files). The shell script runner - the way to
replay a suite of commands without typing them (the point: validate on hardware). Trails
CLAUDE.md; does not amend it.
1. What it is
run <path> reads a script file and executes each command exactly as if you typed it at the
prompt. It is the trivial, sequential case of Appendix D.2 ("cmd1; cmd2") - a command-list
runner in its simplest use - but the gsh LANGUAGE is complete and this said it did not exist.
let / let mut, if / else if / else, switch, fn with parameters and bounded recursion,
import, arithmetic and $() capture are all built (docs/scripting.md, whose own status line reads
COMPLETE). Appendix D's "far-future" framing was overtaken.
gsh> run /suite.gsh
> read /lsr/big.txt
hello world
> result
Ok
> read /lsr/nope
read: not found: /lsr/nope
> result
Err(FileNotFound)
--- summary ---
PASS read /lsr/big.txt
PASS result
FAIL read /lsr/nope
PASS result
--- failures ---
FAIL read /lsr/nope
run: ran 4, failed 1, skipped 0
run <path> <args...> passes the words after the path to the script as $arg1.., $args and
$argcount ($self is the path); run <path> save <out> also writes the run report to a file.
Each command is echoed (> cmd) before it runs, so the serial transcript is
self-documenting - exactly what you want when eyeballing a run on the T630.
2. The script format (.gsh)
- Lines are split on newline; a non-comment line is further split on
;into commands. So a script is either real multi-line, orcmd ; cmd ; cmdon one line. On-device,edit(36_edit.md) writes real multi-line scripts;osdev script-diskbakes one host-side. #comments - a#that starts a line, or follows whitespace outside quotes, starts a comment to the end of the line. Annotate freely.- Blank lines are skipped.
.gshis a naming convention (GodspeedOS shell;.gsis reserved for the future general-purpose Godspeed language), not a mechanism -rundoes not care about the extension (extension-driven behaviour is the hidden magic §26.5 forbids; cf.readnot auto-parsing).
3. Result and the summary
run uses the command Result model (32_result.md): after every command it tracks
Ok/Err, and prints a summary - a --- summary --- list of PASS/FAIL per statement, a
--- failures --- list (and --- skipped --- when anything declined to run), then the tally -
run: ran N, failed M, skipped K
run itself is Ok iff every command was Ok (so result after a run tells you whether
the whole script passed). Today a failing line is one that errors (a missing file, a bad
column, …). Verifying correct output (not just "didn't error") is the job of assert
(34_assert.md) - … | assert contains X, assert fails read /nope - which reads the same
Result.
4. Bounds & safety (loud, never silent - §26.6 / §3.12)
- A script is one
fsfile, streamed in and minified as it loads (comments, blank lines and indentation stripped), soSCRIPT_MAX(7112 bytes = 2 xIO_CHUNK) bounds the CODE, not the raw file. A script whose code does not fit is refused, and none of it runs (run: script CODE exceeds 7112 bytes - refused, none of it was run ...). A read that fails part way is refused the same way (run: could not read all of <path> - ...). - Scripts cannot nest. A
runinside a script is refused (runat depth > 0). This is a hard rule, not a nicety: unboundedrun-calls-runrecursion would overflow the bounded user stack (execute/pipe_runare#[inline(never)]so the per-line nesting stays shallow - the same stack discipline the record builders needed). - A missing or empty script is
run: not found or empty: <path>andErr(FileNotFound).
5. Later (separate so it can grow)
assert- built (utilities/34_assert.md):assert ok/fails <cmd>and… | assert contains X, so a script self-verifies instead of being eyeballed.- Image-baked
.gsh- built:osdev script-disk <out> <script>bakes a script into a GSFS data disk host-side (gsfs_add_file);ddit to the data drive andrun /suite.gshon hardware, no on-device authoring.osdev test scriptproves the loop (incl. piped asserts). - Multi-line authoring on-device - done:
edit(36_edit.md).
6. Implementation shape & conformance
A shell built-in: streams the file in with READ_AT (op 26, like read), minifying as it goes,
resolves import / from ... import at load time, then runs each statement through the gsh
interpreter (run_lines), which hands each command to the same execute() the prompt uses - so
pipes, record verbs,
everything compose for free. Threads the per-line Result as local state (no global, §3.9).
Conforms to 0_conventions.md: its own run help / run version via the shared help_block,
listed under Console in the top-level help.