Safe OS process execution for Elixir.
Combines NIF-based async I/O with a persistent shepherd binary to guarantee zero zombie processes, even under BEAM SIGKILL.
Quick start
# Simple command execution
{output, 0} = NetRunner.run(~w(echo hello))
# Streaming with input
NetRunner.stream!(~w(cat), input: "hello world")
|> Enum.to_list()
# => ["hello world"]
# Piping data through a command
NetRunner.stream!(~w(wc -c), input: "hello")
|> Enum.join()
# => " 5\n"
Summary
Functions
Runs a command and collects all output.
Returns {output, exit_status} where output is the concatenated stdout.
Options
:stderr-:consume(default, captured internally),:redirect(merged with stdout), or:disabled:input- data to write to stdin (binary or enumerable):timeout- maximum wall-clock time in milliseconds. Sends SIGTERM then SIGKILL on timeout. Returns{:error, :timeout}instead of{output, exit_status}.:max_output_size- maximum bytes to collect from stdout. Kills the process and returns{:error, {:max_output_exceeded, partial_output}}if exceeded.
Examples
{output, 0} = NetRunner.run(~w(echo hello))
{"hello\n", 0} = {output, 0}
{output, 0} = NetRunner.run(~w(cat), input: "from stdin")
{:error, :timeout} = NetRunner.run(~w(sleep 100), timeout: 100)
{:error, {:max_output_exceeded, _partial}} =
NetRunner.run(["sh", "-c", "yes"], max_output_size: 1000)
Like stream!/2 but returns {:ok, stream} or {:error, reason}.
Creates a stream for incremental I/O with the command.
Returns a Stream that yields stdout binary chunks.
Raises on process start failure.
Options
:input- data to write to stdin (binary, list, or Stream):stderr-:consume(default),:redirect, or:disabled
Examples
# Stream through a command
NetRunner.stream!(~w(sort))
|> Enum.to_list()
# With input
NetRunner.stream!(~w(tr a-z A-Z), input: "hello")
|> Enum.join()
# => "HELLO"