(std run)

Reference

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 pipeone 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.

See also: run/string, run, Form, running, run/channel, with-run

Reference

Types

Functions

Macros

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.

See also: Form, cmd

Form

union

One thing to run: a command, a pipeline, a redirection, or one bare stage.

FSym
A bare program name, such as sort in 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.

See also: run, Word

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.

See also: run, Form

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 Err if 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 None after a from-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 None after an into-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; Err if 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.

See also: wait/all, 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 wait would.

It observes only: a branch that loses leaves the form running.

See also: wait, 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/string would.

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; Err if 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.

See also: by-lines, exited, Reader

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.

See also: run, kill