std/process
| Function | Result |
|---|---|
capture(command) |
a Result[CommandOutput] with the status, out, and err of a finished command |
capture_input(command, input) |
the same, with input as the command's standard input |
command_text(command) |
the standard output without its final line break, or an ERROR with what the command wrote to standard error when it fails |
has_program(name) |
whether a program can be started, as found on PATH |
A command is a list, the program and then its arguments, each passed as is:
no shell splits or expands them. capture is an ERROR only when the
program cannot be started or does not write UTF-8 text; a command that fails
is OK, with its status.
import "std/process"
match command_text(["git", "rev-parse", "--short", "HEAD"]) do
when OK(commit) then
print("at " + commit)
when ERROR(message) then
eprint(message)
endTo run a command while showing its output as it goes, use the built-in run,
or start_process to keep working while it runs.
Processes on the event loop
spawn(command, options) starts a program and gives a Process at once.
While the loop of std/loop runs, its output arrives in
callbacks as the program writes it, and on_exit says when it has ended,
once all its output has arrived:
import "std/loop"
import "std/process"
Process build = spawn(["make", "all"], SpawnOptions())?
on_output_lines(build, func(str line) do
print("make:", line)
end)
on_exit(build, func(int code) do
print("make ended with", code)
end)
run_loop()SpawnOptions sets how it starts:
| Field | Meaning |
|---|---|
dir |
the directory it works in; "" for this program's |
env, clear_env |
variables added to the environment, or with clear_env all of it |
output, errors, input |
each stream: Stdio.PIPE (the default, read or written on the loop), INHERIT (this program's), DISCARD, or FILE(path) |
new_group, new_session |
a process group, or a session, of its own |
hide_window |
no console window on Windows |
| Function | Result |
|---|---|
on_output(p, callback), on_errors(p, callback) |
the bytes as they come, and empty bytes at the end |
on_output_lines(p, callback), on_error_lines(p, callback) |
each line as text, without its line end |
on_exit(p, callback) |
the exit code; on POSIX, 128 and the number of a signal that ended it |
write_input(p, data), write_input_text(p, text) |
queues input, written as the process reads it; gives how many bytes wait |
input_pending(p), on_drain(p, callback) |
the bytes that wait, and a callback when they have all been written |
close_input(p) |
closes the input once what waits is written |
kill(p, signal) |
sends "terminate", "kill", "interrupt", or another signal |
kill_tree(p) |
ends the process and every process it started |
finished(p) |
a Task[int] that settles with the exit code, as on_exit says, in its place |
capture_task(command) |
runs a command on the loop, with no input: a Task[CommandOutput] that settles as capture would return |
Pseudo-terminals
spawn_pty(command, options) starts a program on a pseudo-terminal of its
own, as it would run in a terminal window, the way a terminal emulator or
an editor's terminal panel runs a shell. The program sees a terminal: it
can ask for its size, move the cursor, and use colors, and Ctrl+C reaches
it as an interrupt. It is a Process like any other, so its output, with
the terminal's echo of what it is sent, comes to on_output, what
write_input sends is typed into it ("\r" is Enter and "\x03" is
Ctrl+C), and on_exit, kill, and kill_tree work as they do for
spawn:
PtyOptions options = PtyOptions()
options.columns = 120
options.rows = 40
Process shell = spawn_pty(["bash"], options)?
on_output(shell, func(bytes chunk) do
write_out_bytes(chunk)
end)
write_input_text(shell, "ls --color\r")PtyOptions has the terminal's columns and rows (80 and 24), and
dir, env, and clear_env as for spawn. On POSIX, TERM is its
term ("xterm-256color") and COLORTERM is "truecolor", unless env
sets them.
| Function | Result |
|---|---|
spawn_pty(command, options) |
a Result[Process] |
resize_pty(p, columns, rows) |
gives the terminal a new size, which the program hears of as a window change; says whether the terminal was still there |
foreground_name(p) |
the name of the program in the terminal's foreground, such as the command a shell runs, on Linux and macOS; NONE elsewhere |
On POSIX the terminal is a pair from posix_openpt, and the program leads
a session of its own with the terminal as its controlling terminal. On
Windows it is a pseudo-console (ConPTY), from Windows 10 version 1809; what
comes out is what the pseudo-console draws, the text with the sequences
that place and color it, rather than the bytes the program wrote.
A bare program name is looked up on PATH, and the built-in find_program
gives the path it finds. A program that ends without reading its input
drops the rest of it. On Windows each process runs in a job object, so
kill_tree reaches every process it started; on POSIX it needs the process
started with new_group or new_session, and ends its group. A process's
pid is the id the system gives it.