Spawn a child process with stdio pipes for bidirectional communication.
child = Cmd.new_str("node").arg_str("repl.js").spawn!()?
child.write_stdin!(Str.to_utf8("1+1\n"))?
response = child.read_stdout!(100)?
child.kill!()?
Cmd :: # (opaque)
Build and run child processes with native-safe programs, arguments, and environment values.
Spawn a child process with stdio pipes for bidirectional communication.
child = Cmd.new_str("node").arg_str("repl.js").spawn!()?
child.write_stdin!(Str.to_utf8("1+1\n"))?
response = child.read_stdout!(100)?
child.kill!()?
spawn_grouped! : Cmd => Try(Child, [SpawnFailed(IOErr), ..])
Spawn a child process that gets cleaned up when the parent exits.
Use this for test servers, subprocesses, or anything that shouldn't outlive your program.
**Linux and Windows**: children are guaranteed to die with the parent,
even on SIGKILL (via PR_SET_PDEATHSIG / Job Objects). **macOS**: children
die on normal exit, Ctrl+C, and crashes, but may survive kill -9 of the
parent (kernel limitation).
kill_grouped! : { } => Try({ }, [KillFailed(IOErr), ..])
Kill all processes spawned via [Cmd.spawn_grouped!] and their children.
This is called automatically on normal program exit, but you can call it explicitly for immediate cleanup.
exec! : OsStr, List(OsStr) => Try({ }, [ExecFailed({ command : Str, exit_code : I32 }), FailedToGetExitCode({ command : Str, err : IOErr }), ..])
Simplest way to execute a command by name with arguments. Stdin, stdout, and stderr are inherited from the parent process.
If you want to capture the output, use [exec_output!] instead.
Cmd.exec!("echo", ["hello world"])?
exec_cmd! : Cmd => Try({ }, [ExecCmdFailed({ command : Str, exit_code : I32 }), FailedToGetExitCode({ command : Str, err : IOErr }), ..])
Execute a Cmd (using the builder pattern). Stdin, stdout, and stderr are inherited from the parent process.
You should prefer using [exec!] instead, only use this if you want to use env, envs or clear_envs.
If you want to capture the output, use [exec_output!] instead.
Cmd.new("cargo")
.arg(["build")
.env("RUST_BACKTRACE", "1")
.exec_cmd!()?
exec_output! : Cmd => Try({ stdout_utf8 : Str, stderr_utf8_lossy : Str }, [StdoutContainsInvalidUtf8({ cmd_str : Str, err : [BadUtf8({ problem : _, index : U64 })] }), NonZeroExitCode({ command : Str, exit_code : I32, stdout_utf8_lossy : Str, stderr_utf8_lossy : Str }), FailedToGetExitCode({ command : Str, err : IOErr }), ..])
Execute command and capture stdout and stderr as UTF-8 strings. Invalid UTF-8 sequences are replaced with the Unicode replacement character.
Use [exec_output_bytes!] instead if you want to capture the output in the original form as bytes. [exec_output_bytes!] may also be used for maximum performance, because you may be able to avoid unnecessary UTF-8 conversions.
cmd_output =
Cmd.new("echo")
.args(["Hi"])
.exec_output!()?
Stdout.line!("Echo output: ${cmd_output.stdout_utf8}")?
exec_output_bytes! : Cmd => Try({ stderr_bytes : List(U8), stdout_bytes : List(U8) }, [NonZeroExitCodeB({ exit_code : I32, stdout_bytes : List(U8), stderr_bytes : List(U8) }), FailedToGetExitCodeB(IOErr), ..])
Execute command and capture stdout and stderr in the original form as bytes.
Use [exec_output!] instead if you want to get the output as UTF-8 strings.
cmd_output =
Cmd.new("echo")
.args(["Hi"])
.exec_output_bytes!()?
Stdout.line!("${Str.inspect(cmd_output_bytes)}")? # {stderr_bytes: [], stdout_bytes: [72, 105, 10]}
exec_exit_code! : Cmd => Try(I32, [FailedToGetExitCode({ command : Str, err : IOErr }), ..])
Execute a command and return its exit code. Stdin, stdout, and stderr are inherited from the parent process.
You should prefer using [exec!] or [exec_cmd!] instead, only use this if you want to take a specific action based on a **specific non-zero exit code**.
For example, roc check returns exit code 1 if there are errors, and exit code 2 if there are only warnings.
So, you could use exec_exit_code! to ignore warnings on roc check.
exit_code = Cmd.new("cat").arg("non_existent.txt").exec_exit_code!()?
Create a new command with the given program name. Use a function that starts with exec_ to execute it.
cmd = Cmd.new("ls")
Create a new command from a Roc string.
Add a single argument to the command.
❗ Shell features like variable subsitition (e.g. $FOO), glob patterns (e.g. *.txt), ... are not available.
cmd = Cmd.new("ls").arg("-l")
Add a single string argument to the command.
Add multiple arguments to the command.
❗ Shell features like variable subsitition (e.g. $FOO), glob patterns (e.g. *.txt), ... are not available.
cmd = Cmd.new("ls").args(["-l", "-a"])
Add multiple string arguments to the command.
Add a single environment variable to the command.
cmd = Cmd.new("env").env("FOO", "bar") # add the environment variable "FOO" with value "bar"
Add a single string environment variable to the command.
Add multiple environment variables to the command.
cmd = Cmd.new("env").envs([("FOO", "bar"), ("BAZ", "qux")])
Add multiple string environment variables to the command.
clear_envs : Cmd -> Cmd
Clear all environment variables before running the command.
Only environment variables added via env or envs will be available.
Useful if you want a clean command run that does not behave unexpectedly if the user has some env var set.
cmd =
Cmd.new("env")
.clear_envs()
.env("ONLY_THIS", "visible")
Render a command configuration as a stable, escaped string.
to_inspect : Cmd -> Str
Customize command output for Str.inspect.
Cmd.Child :: # (opaque)
A spawned child process with stdio pipes (see [Cmd.spawn!] and [Cmd.spawn_grouped!]).
**Important**: read_stdout! and read_stderr! block until *exactly* N bytes
have been read. If the stream reaches EOF before N bytes are available, the
call returns ReadFailed. Use these when you know the exact message size
(e.g., length-prefixed protocols) or use wait! to read all output at once.
Call close_stdin! to signal EOF to the child process. Many programs
(grep, cat, etc.) wait for stdin EOF before producing output.
Remember to call kill! or wait! when done to clean up resources.
to_inspect : Child -> Str
Render the child without exposing its host handle.
write_stdin! : Child, List(U8) => Try({ }, [WriteFailed(IOErr), ..])
Write bytes to the child's stdin.
Read exactly num_bytes bytes from the child's stdout (blocking).
Read exactly num_bytes bytes from the child's stderr (blocking).
close_stdin! : Child => Try({ }, [CloseFailed(IOErr), ..])
Close the child's stdin, signalling EOF.
Kill the child process. For children spawned with [Cmd.spawn_grouped!], this kills the whole process tree.
wait! : Child => Try({ exit_code : I32, stdout : List(U8), stderr : List(U8) }, [WaitFailed(IOErr), ..])
Wait for the child to exit, returning its exit code and any remaining output.
poll! : Child => Try([Exited({ exit_code : I32, stdout : List(U8), stderr : List(U8) }), Running], [PollFailed(IOErr), ..])
Check whether the child has exited, without blocking.
Returns Running if the process is still executing, or
Exited({ exit_code, stdout, stderr }) once it has finished. After
returning Exited, the process is cleaned up; subsequent calls fail.