fence/bash
Symbol: fence/bash
Use-case: Capture a bash script verbatim and run it asynchronously, getting back a result object. The fence body is the script; the surrounding Koskari code launches it and inspects the outcome.
Behaviour: By default the fence evaluates to an async callable.
Invoking it runs the script through bash -c and returns a
ProcessResult. Positional arguments passed to the callable
become the script’s positional parameters $1, $2, … (and so $@), each
coerced to a string. With the immediate: True option there is no callable:
the fence expands to the run call in place, so the fence expression itself
evaluates to the ProcessResult.
A nonzero exit status is reported on the result, never raised.
Syntax:
```bash [immediate: True]
SCRIPT LINE
...
```
The only accepted option is immediate: (a True/False literal); any other
opener-line option raises FenceError.
Examples:
>>> var rev ```bash
... echo -n "$@" | rev
... ```
>>> var ohai (rev "Hello" 123 "World")
>>> ohai
<ProcessResult 'bash' returncode=0>
>>> ohai.text
"dlroW 321 olleH"
;; immediate: True -- the fence is the ProcessResult, no callable
var host ```bash immediate: True
hostname -f
```
var name host.text
ProcessResult
ProcessResult (from koskari.asyncio) is the captured outcome of a finished
process – the subprocess analogue of an HTTP client’s Response: capture
everything, interpret afterwards.
Member |
Meaning |
|---|---|
|
the argv tuple that was run |
|
the process exit status |
|
raw captured bytes |
|
stdout / stderr decoded as UTF-8 |
|
stdout parsed as one JSON document |
|
stdout parsed as JSON Lines (one document per non-blank line) |
|
stdout parsed as one YAML document (requires PyYAML) |
|
raise |
Because raise_for_status returns the result, strict-and-parsed reads chain:
var summary (.json (.raise_for_status (report)))
Implementation
fence/bash is defined in Koskari, in koskari/bootstrap/_fences.ki, through
the define-fence syntax – it is not Python code. The handler receives the
raw script text and the metadata dict and returns Koskari source:
define-fence fence/bash [raw meta]:
var options (meta.get "options")
var exec_now (options.pop "immediate" False)
when options:
var names (.join " " (sorted options))
raise (FenceError f"fence/bash got unknown options: {names}")
switch exec_now:
case [True]:
`(run-process "bash" "-c" ,raw)
case [False]:
`function <fence/bash> [*: args]:
set! args (map str args)
run-process "bash" "-c" ,raw "bash-fence" *: args
else:
raise (FenceError f"fence/bash got unknown exec_now: {exec_now}")
Notes:
immediate:is matched as a literal. Theswitchcompares the source value against theTrue/Falseliterals, not for truthiness, so only an explicitimmediate: Trueselects in-place mode; anything else is an error rather than a silently-truthy match.run-processis a universal builtin (koskari.asyncio), so the expansion needs no import at the use site. It wrapsasyncio.create_subprocess_execpluscommunicateinto one awaited call and returns aProcessResult.Positional arguments start at
$1. The generated callable passes"bash-fence"as the first word after the script, which bash assigns to$0; the caller’s arguments therefore fill$1,$2, … The(map str args)coercion means non-string arguments (e.g. the123above) reach the script as their string form.No shell injection surface. Arguments are passed as discrete
argventries tocreate_subprocess_exec(anexecve, not a shell string), so they are never re-tokenized by a shell – the safe,shell=False-equivalent path.
Runtime: koskari.asyncio (run-process, ProcessResult).