Skip to content

std.command

std.command is the standard subprocess facade for Janus code that needs to run other programs.

It follows an argv-first model: run*, output*, and spawn* pass arguments directly to the target binary. They do not perform shell interpolation, glob expansion, redirects, or pipe parsing.

Use shell and shell_output only when shell behavior is the feature.

Use the fixed-arity helpers for short calls, or the *_args helpers when the argument list is already a slice.

use std.command

The synchronous run* functions return the child process exit code:

if command.run("true") != 0 do
eprintln("true failed")
end
if command.run3("test", "alpha", "=", "alpha") != 0 do
eprintln("comparison failed")
end
if command.run4("test", "!", "alpha", "=", "beta") != 0 do
eprintln("negated comparison failed")
end

Current fixed-arity calls:

  • run(program)
  • run1(program, arg1)
  • run2(program, arg1, arg2)
  • run3(program, arg1, arg2, arg3)
  • run4(program, arg1, arg2, arg3, arg4)
  • run_args(program, args)

Use run_args for variable argv lists:

const args: [3][]const u8 = .{"alpha", "=", "alpha"}
if command.run_args("test", args[0..3]) != 0 do
eprintln("comparison failed")
end

Use output* when stdout should be captured into a caller-provided buffer. The return value is the number of bytes written, or -1 when command execution fails.

var out: [64]u8 = undefined
let n = command.output1("printf", "janus", out[0..64])
if n < 0 do
eprintln("printf failed")
end
let joined = command.output3("printf", "%s%s", "ja", "nus", out[0..64])

Current capture calls:

  • output(program, out)
  • output1(program, arg1, out)
  • output2(program, arg1, arg2, out)
  • output3(program, arg1, arg2, arg3, out)
  • output_args(program, args, out)
const args: [3][]const u8 = .{"%s%s", "ja", "nus"}
let n = command.output_args("printf", args[0..3], out[0..64])

Use capture* when the caller needs an exit code plus separate stdout and stderr buffers.

var out: [64]u8 = undefined
var err: [64]u8 = undefined
let result = command.capture2(
"sh",
"-c",
"printf out; printf err >&2; exit 3",
out[0..64],
err[0..64]
)
if result.code != 0 do
eprintln("command failed")
end

CommandResult contains:

  • code: process exit code, or -1 for local execution setup failure
  • stdout_len: bytes captured into the stdout buffer
  • stderr_len: bytes captured into the stderr buffer
  • timed_out: 1 when a timeout killed the child, otherwise 0

Current result-capture calls:

  • capture(program, stdout_buf, stderr_buf)
  • capture1(program, arg1, stdout_buf, stderr_buf)
  • capture2(program, arg1, arg2, stdout_buf, stderr_buf)
  • capture3(program, arg1, arg2, arg3, stdout_buf, stderr_buf)
  • capture_args(program, args, stdout_buf, stderr_buf)

Use timeout capture when a subprocess must not be allowed to run forever. Timeouts are expressed in milliseconds. A timed-out process returns CommandResult { code: -2, timed_out: 1, ... }.

var out: [64]u8 = undefined
var err: [64]u8 = undefined
let result = command.capture1_timeout_ms(
"sleep",
"2",
100,
out[0..64],
err[0..64]
)
if result.timed_out == 1 do
eprintln("child exceeded deadline")
end

Current timeout calls:

  • capture1_timeout_ms(program, arg1, timeout_ms, stdout_buf, stderr_buf)
  • capture2_timeout_ms(program, arg1, arg2, timeout_ms, stdout_buf, stderr_buf)

Use spawn* for daemon-style workflows where the parent needs a child handle before waiting.

let child = command.spawn1("sleep", "1")
let code = command.wait(child)
let shell_child = command.spawn2("sh", "-c", "exit 0")
let shell_code = command.wait(shell_child)

Current spawn calls:

  • spawn(program)
  • spawn1(program, arg1)
  • spawn2(program, arg1, arg2)
  • spawn3(program, arg1, arg2, arg3)
  • spawn_args(program, args)
  • wait(child)
  • kill(child)

has(program) returns 1 when a command can be found through PATH, otherwise 0. The lookup is direct PATH probing, not a shell-built which command.

if command.has("rg") == 1 do
_ = command.run2("rg", "--files", ".")
end

Shell execution is intentionally explicit:

let code = command.shell("printf janus | wc -c")

Use this only when the shell syntax is part of the program. Prefer run*, output*, and spawn* for ordinary argument passing.