Overview
Running programs: pipelines and redirections written as quoted forms.
(import (std run))
(run/string '(pipe (cat "hej.txt") (wc -l)))
(run/status '(into-file "out.txt" (from-file "in.txt" (pipe (grep "x") sort))))
;; From inside a bjoroutine: lines as they come, until the form exits.
(match (run/channel '(cat "log.txt") by-lines)
((Err e) 0)
((Ok (Tuple items p))
(let go ((n 0))
(match (sync (choose (wrap (chan-recv items) (fun (line) (Got line)))
(wrap (exited p) (fun (r) Ended))))
((Got line) (go (+ n 1)))
(Ended n)))))
A form is one thing to run, written as a quoted literal.
The grammar.
'(cat "hej.txt") | run a program |
'(sort), or sort in a pipe | one taking no arguments |
'(pipe (cat "a") (wc -l)) | connect them |
'(from-file "in.txt" (wc -l)) | stdin from a file |
'(into-file "out.txt" (ls)) | stdout to a file, truncating |
'(append-to-file "log" (date)) | stdout to a file, appending |
'(errors-into-file "e" (make)) | stderr of every command inside |
'(errors-append-to-file "e" (make)) | the same, appending |
'(,(cmd program "-l")) | a computed program name |
'(pipe (cat "x") ,my-filter) | a stage written in Bjolang |
'(grep ["-i" "bomb"]) | splice a computed argv |
'("pipe" "-x") | the program called pipe |
Redirections nest:
(into-file "out" (from-file "in" (pipe (tr "a" "b") sort))).
pipe, from-file and the rest are tags: the head of a form
names its case, and the name, the arity and every argument are checked at
compile time. A head that names no tag is a command.
A word is a symbol, string, int, double, [...] argv vector, nested
form, unquoted Cmd or unquoted Filter: eight cases, and
nothing else. A character is a type error where it is written. One word is
one argument, spaces and all; nothing re-splits it. A double is written
the same on every machine, 0.5 and never 0,5.
A command’s program is looked up on PATH, and its standard error is
inherited unless errors-into-file or errors-append-to-file
says otherwise.
Blocking or not. run/string, run/strings,
run/status, run/output and wait block, which is
right in an ordinary function. Inside a bjoroutine, blocking parks a pool
thread the fibers need: use exited, running or
run/channel, or (blocking ...).
Gotchas.
- Close the input, and drain the output, or the first stage never
sees end of file and
waitnever returns. - A form is one thing:
'((cat "a") (wc -l))is refused. Saypipe. - A bare tag in stage position is a type error;
'("into-file" ...)is the program of that name. - Piping out of a redirect, or redirecting an end twice, is refused.
- After
into-file,run/stringgives"". Userun/status. - stderr is inherited unless
errors-into-filesays otherwise. - A filter must not close its output port, and a raising one
surfaces through
waitrather than as an exit code. - The blocking entry points inside a bjoroutine park a pool thread.
- One word is one argument, spaces and all; doubles render invariantly.
See also: run/string, run, Form, running, run/channel, with-run
Reference
Types
Word
union
One word of a command in a form.
WSym- A symbol, used as its name.
WStr- A string, as it is.
WInt- An int.
WDouble- A double, written the same on every machine.
WArgv- A computed argv,
[...], spliced in as several arguments. WCmd- An unquoted
Cmd. WFilter- An unquoted
Filter. WForm- A nested form.
A form’s words are elaborated into these cases where the literal is
written, which is why the type is transparent. Only symbols, strings,
ints, doubles and argv vectors are plain words; the rest stand for a whole
stage, and among a command’s arguments they are an Err from
run.
Form
union
One thing to run: a command, a pipeline, a redirection, or one bare stage.
FSym- A bare program name, such as
sortin a pipe. FStr- A bare program name written as a string.
FArgv- A bare computed argv: the program and its arguments.
FCmdValue- A bare
,(cmd ...). FFilter- A bare
,filter. FCmd- A command:
(echo "x"). FPipe(pipe form ...): each form's output into the next one's input.FFrom(from-file path form): stdin from a file.FInto(into-file path form): stdout to a file, truncating it.FAppend(append-to-file path form): stdout to a file, appending.FErrInto(errors-into-file path form): stderr of every command inside to a file, truncating it.FErrAppend(errors-append-to-file path form): the same, appending.
Written as a quoted literal; the module’s documentation has the grammar.
The tagged cases are checked where the form is written: the name, the
number of arguments and every position. What no tag names is a command,
so '(sort) and '(echo "x") are commands. A pipeline takes
any number of stages.
Cmd
record
A command and its arguments, for a program name that is computed rather than spelled.
program- The program, looked up on
PATH. arguments- Its arguments, one word each.
See also: cmd
Filter
type alias
A stage written in Bjolang: read the input to its end, write the output, return.
(: shout Filter)
(defbjo (shout in out)
(write-string out (string-upcase (read-all in)))
unit)
(run/string '(pipe (cat "x") ,shout))
A defbjo, so it may sync. Do not close the output
port: run does that when the filter returns. A filter that raises
surfaces through wait as an Err, not as an exit code.
Reader
type alias
How run/channel turns a form’s output into items on a channel.
%a- What an item is.
A defbjo given the output port and the channel. It sends what it
reads and returns when it is done; it runs as a stage of its own, so
wait and exited cover it.
See also: run/channel, by-lines
Proc
record
A started form: its two ends, and what to wait for.
See also: run, proc-input, proc-output, wait, kill
Functions
cmd
function
(: cmd (-> string #:rest string Cmd))
(cmd program #:rest arguments)
A command with a computed program name, for ,(cmd ...) in a form.
program- The program.
arguments ...- Its arguments, one word each.
- returns
- The command.
(run/string '(,(cmd program "-l")))
See also: Cmd
run
function
(: run (-> Form (Result Exception Proc)))
(run form)
Starts a form; both ends are yours.
form- What to run.
- returns
- The running form, or
Errif the form is malformed, a program cannot be started or a file cannot be opened.
Every other entry point is built on this one. Nothing is waited for:
write to proc-input and close it, drain proc-output, then
wait. A form that fails part-way through starting kills what it
had already started.
See also: proc-input, proc-output, wait, kill, with-run
run/string
function
(: run/string (-> Form (Result Exception string)))
(run/string form)
Runs a form and answers its standard output.
form- What to run.
- returns
- Everything it wrote, once it has exited. The exit code is dropped.
Its input is closed at once. After an into-file there is no output
to read, and this answers "": use run/status.
See also: run/output, run/strings, run/status
run/strings
function
(: run/strings (-> Form (Result Exception (Vec string))))
(run/strings form)
Runs a form and answers its standard output, by line.
form- What to run.
- returns
- Its lines, once it has exited. The exit code is dropped.
See also: run/string
run/status
function
(: run/status (-> Form (Result Exception int)))
(run/status form)
Runs a form, throws away its output, and answers its exit code.
form- What to run.
- returns
- The last command's exit code, or 0 if it has none.
See also: run/output, wait
run/output
function
(: run/output (-> Form (Result Exception (Tuple int string))))
(run/output form)
Runs a form and answers its exit code and its output, together.
form- What to run.
- returns
- The last command's exit code and everything the form wrote.
For a command whose failure is an ordinary answer:
git show v1.0.0:manifest.bjodat on a tag that has no manifest
prints nothing and exits non-zero, which is not the same as a tag whose
manifest is empty. Both halves come from one run.
See also: run/string, run/status
proc-input
function
(: proc-input (-> Proc (Option TextOutputPort)))
(proc-input p)
Where to write the form’s input.
p- The running form.
- returns
- The port, or
Noneafter afrom-file.
Closing it is what ends the first stage: until it is closed, the first stage waits for more.
See also: proc-output
proc-output
function
(: proc-output (-> Proc (Option TextInputPort)))
(proc-output p)
Where to read the form’s output.
p- The running form.
- returns
- The port, or
Noneafter aninto-file.
It has to be drained, or the last stage blocks writing and wait
never returns.
See also: proc-input
wait
function
(: wait (-> Proc (Result Exception int)))
(wait p)
Waits for a form to finish, blocking.
p- The running form.
- returns
- The last command's exit code, or 0 if it has none;
Errif a filter or a redirection failed.
Close the input and drain the output first, or it never returns. Inside a
bjoroutine it parks a pool thread: use exited.
wait/all
function
(: wait/all (-> Proc (Result Exception (Vec int))))
(wait/all p)
Waits for a form to finish, blocking, and answers every exit code.
p- The running form.
- returns
- Every command's exit code, in the order they were started. Filters have none; their failures are the
Err.
See also: wait
kill
function
(: kill (-> Proc void))
(kill p)
Stops every program a form started.
p- The running form.
One that has already exited is passed over. The copying between stages ends by itself once the streams it copies do.
See also: with-run
exited
function
(: exited (-> Proc (Event (Result Exception int))))
(exited p)
An event for a form’s exit.
p- The running form.
- returns
- An event answering what
waitwould.
It observes only: a branch that loses leaves the form running.
running
function
(: running (-> Form (Event (Result Exception string))))
(running form)
A whole form as one event, answering its standard output.
form- What to run.
- returns
- An event answering what
run/stringwould.
It owns the form: nothing starts until the branch is reached, the input is closed at once, and a branch that loses kills it.
See also: exited, run/string
run/channel
function
(: run/channel (-> Form (Reader %a) (Result Exception (Tuple (Chan %a) Proc))))
(run/channel form read)
Runs a form and sends its output onto a channel, as items.
form- What to run.
read- Turns the output into items.
- returns
- The channel and the running form;
Errif it cannot start, or its output goes to a file.
The reader runs as a stage of the form, so wait and exited
cover it: the form has not exited until the reader has returned.
by-lines
function
(: by-lines (Reader string))
(by-lines out items)
The stock Reader: one item per line.
out- The output to read.
items- Where to send the lines.
- returns
unit, once every line has been sent.
Line ends, \r\n included, and a missing last newline are handled
by .NET’s TextReader. Each line is sent as soon as it is read, so
the lines of a program whose output never ends, tail -f, still
arrive, and the output is never held whole.
See also: run/channel
Macros
with-run
macro
(with-run (name form) body ...)
Runs a form for the extent of body, and kills it on the way out.
name- Bound to the
(Result Exception Proc). form- What to run.
body ...- What to run with it. At least one form.
(with-run (p '(ls "-l"))
(match p
((Ok proc) (println "started"))
((Err e) (println "could not start"))))
The form is killed however the body leaves. A macro, so the body may
sync.