Skip to main content

49  os standard library

The os module provides safe, high-level abstractions over POSIX file descriptors, environment variables, working-directory inspection, shell command execution, and shell-free argument-array subprocess management with concurrent pipe I/O.

#use io
#use os

out = os::run_args("printf", os::Args("%s-%s", "edva", "42")) | s => s | ""
io::out $ out

49.1 Types and Constants

Symbol Kind Definition Description
os::Args Growable Array String{} Argument array passed to spawn_args, exec_args, exec_input, run_args, spawn_piped, and spawn_bg
os::ExecResult Record (status: Int, output: String) Exit status and captured stdout from os::exec
os::ProcResult Record (status: Int, stdout: String, stderr: String) Exit status and separately captured stdout and stderr
os::Child Record (pid: Int, stdin_fd: Int, stdout_fd: Int, stderr_fd: Int) Active child process handle with pipe file descriptors
os::SpawnOpts Record (cwd: String, env: EnvVars, clear_env: <>) Working directory and environment overrides for subprocesses
os::Pipe Record (r: Int, w: Int) Anonymous POSIX pipe read/write descriptor pair
os::WinSize Record (rows: Int, cols: Int) Terminal/PTY window dimensions
os::Pty Record (master_fd: Int, slave_fd: Int, name: String) Allocated pseudo-terminal master/slave pair and device path
os::PtyChild Record (pid: Int, master_fd: Int, name: String) Interactive child process attached to a controlling PTY
os::Children Growable Array Child{} Collection of piped child handles passed to multiplex_children
os::ProcResults Growable Array ProcResult{} Multiplexed completion results returned by multiplex_children
os::SIGINT Constant 2 Interrupt signal (SIGINT)
os::SIGKILL Constant 9 Unconditional termination signal (SIGKILL)
os::SIGTERM Constant 15 Graceful termination signal (SIGTERM)

49.2 Function catalog

Category Function Signature Description
Descriptors & Terminal os::open(path, flags) String, Int => Int Opens file path with flags, returning file descriptor
os::close(fd) Int => Int Closes file descriptor
os::write(fd, buf, count) Int, String, Int => Int Writes string byte buffer to descriptor
os::read(fd, count) Int, Int => String Unbuffered read of up to count bytes into an immutable String
os::ioctl(fd, req, arg) Int, Int, Int => Int Performs control device request
os::isatty(fd) Int => <> Returns <+> if fd refers to a terminal device
os::pipe() () => < Pipe | > Creates an anonymous POSIX pipe pair (r, w)
os::set_nonblocking(fd) Int => <> Sets O_NONBLOCK on descriptor fd
os::try_read(fd, count) Int, Int => < String | > Non-blocking read (<+ "" +> on EAGAIN, <--> on EOF/error)
Environment os::env(name) String => < String | > Looks up environment variable name
os::env_or(name, fallback) String, String => String Returns environment variable name or fallback if unset
os::setenv(name, val) String, String => <> Sets environment variable name to val (overwriting)
os::unsetenv(name) String => <> Removes environment variable name
Process & Host os::cwd() () => String Returns the current working directory
os::chdir(path) String => <> Changes the current working directory to path
os::pid() () => Int Returns the current process ID
os::ppid() () => Int Returns the parent process ID
os::hostname() () => String Returns the system hostname
os::which(prog) String => < String | > Searches $PATH for executable prog
Subprocess (Direct Args) os::spawn_args(prog, args) String, Args => Int Spawns prog with args (inheriting stdio), waits, and returns exit status (-1 on spawn failure)
os::exec_args(prog, args) String, Args => < ProcResult | > Spawns prog with args (no shell) and captures stdout, stderr, and status
os::exec_input(prog, args, input) String, Args, String => < ProcResult | > Spawns prog with args, feeds input to stdin, and captures stdout, stderr, and status
os::run_args(prog, args) String, Args => < String | > Runs prog with args and returns <+ stdout +> if exit status is 0
Background & Piped Children os::spawn_bg(prog, args) String, Args => < Int | > Spawns prog in background (inheriting stdio) and returns <+ child_pid +>
os::spawn_piped(prog, args) String, Args => < Child | > Spawns prog with piped stdin_fd, stdout_fd, and stderr_fd
os::communicate_child(child, input) Child, String => < ProcResult | > Feeds input to child, drains stdout/stderr via poll, and waits for exit
os::wait_child(child) Child => < ProcResult | > Drains remaining stdout/stderr from child and waits for exit
os::wait_pid(pid) Int => < Int | > Waits for pid to exit and returns decoded exit code
os::try_wait_pid(pid) Int => < Int | > Non-blocking check (WNOHANG); returns <+ status +> if exited or <--> if still running
os::wait_pid_timeout(pid, ms) Int, Int => < Int | > Waits up to ms milliseconds for pid to exit (<--> on timeout)
os::kill_pid(pid, sig) Int, Int => <> Sends signal sig to pid
os::spawn_opts() () => SpawnOpts Creates default SpawnOpts (inherited cwd and environment)
os::with_cwd(opts, dir) SpawnOpts, String => SpawnOpts Returns SpawnOpts with working directory dir
os::with_env(opts, key, val) SpawnOpts, String, String => SpawnOpts Appends environment override key = val to opts
os::with_clear_env(opts, flag) SpawnOpts, <> => SpawnOpts Configures whether child clears inherited environment before applying overrides
os::spawn_piped_opts(prog, args, opts) String, Args, SpawnOpts => < Child | > Spawns prog with piped stdio, working directory, and environment overrides
os::spawn_bg_opts(prog, args, opts) String, Args, SpawnOpts => < Int | > Spawns prog in background with SpawnOpts
os::exec_opts(prog, args, opts, input) String, Args, SpawnOpts, String => < ProcResult | > Runs prog with SpawnOpts and input, capturing stdout and stderr
os::communicate_child_timeout(child, input, ms) Child, String, Int => < ProcResult | > Drains child pipes within ms; sends SIGKILL and returns <--> on timeout
os::exec_timeout(prog, args, input, ms) String, Args, String, Int => < ProcResult | > Spawns prog and captures output within ms, killing child on timeout
os::multiplex_children(children, ms) Children, Int => ProcResults Multiplexes stdout/stderr pipes across multiple children in parallel
Pseudo-Terminals (PTY) os::pty_open(rows, cols) Int, Int => < Pty | > Allocates a POSIX pseudo-terminal pair (master_fd, slave_fd, name)
os::pty_resize(fd, rows, cols) Int, Int, Int => <> Updates PTY window dimensions via TIOCSWINSZ
os::pty_size(fd) Int => < WinSize | > Queries PTY window dimensions via TIOCGWINSZ
os::spawn_pty(prog, args, rows, cols) String, Args, Int, Int => < PtyChild | > Spawns prog in a new session attached to a controlling (rows, cols) PTY
os::spawn_pty_opts(prog, args, rows, cols, opts) String, Args, Int, Int, SpawnOpts => < PtyChild | > Spawns prog in a controlling PTY with SpawnOpts
os::communicate_pty(pty, input, ms) PtyChild, String, Int => < ExecResult | > Feeds input to pty.master_fd, drains PTY output within ms, and waits for exit
Shell & Raw posix_spawn os::system(cmd) String => Int Runs cmd via /bin/sh -c and returns decoded exit status
os::exec(cmd) String => < ExecResult | > Runs cmd via popen and returns (status, output)
os::run(cmd) String => < String | > Runs cmd via popen and returns <+ output +> when status is 0
os::spawn(path, argv) String, Addr => Int Low-level posix_spawn with raw Addr argv pointer
Low-Level Process Primitives os::fork! () => Int fork(2): child pid in the parent, 0 in the child, negative on failure (errno set)
os::dup2(old_fd, new_fd) Int, Int => <> dup2(2): duplicates old_fd onto new_fd; <+> on success
os::exit_now(status) Int => () _exit(2): terminates immediately without atexit handlers or stdio flush (use in forked children)
os::socketpair! () => < (Int, Int) | > Connected AF_UNIX stream socket pair with close-on-exec set on both ends
os::set_parent_death_signal(sig) Int => <> Linux prctl(PR_SET_PDEATHSIG): deliver sig when the parent exits; always <-> on other platforms

49.3 Usage examples

49.3.1 Capturing stdout, stderr, and feeding stdin without shell injection

#use io
#use os

res = os::exec_input("tr", os::Args("a-z", "A-Z"), "hello edva")
res
   | r => io::out $ r.stdout
   | io::out $ "failed"

49.3.2 Working directory, environment overrides, and parallel process multiplexing

#use io
#use os

opts = os::with_env(os::with_cwd(os::spawn_opts!, "/tmp"), "EDVA_MODE", "fast")
c0 = os::spawn_piped_opts("sh", os::Args("-c", "printf '%s' \"$EDVA_MODE\""), opts)!!
c1 = os::spawn_piped("printf", os::Args("parallel-ok"))!!

results = os::multiplex_children(os::Children(c0, c1), 2000)
io::out $ (results(0)!!).stdout + ":" + (results(1)!!).stdout