Terminal Commands

Different ways to run commands like you do in a terminal. These functions are identical on basic-webserver.

Code

app [main!] {
	cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.21.0/4rAQg8kUYZ3Vksr4qMQHpaFYNiHSn9GgS7gVxghd1XYV.tar.zst",
	roc: "nightly-2026-08-12-606470f",
}

import cli.Stdout
import cli.Cmd
import cli.OsStr

# Different ways to run commands like you do in a terminal.

main! = |_args| {
	# Simplest way to execute a command (prints to your terminal).
	Cmd.exec!("echo", ["Hello"])?

	# To execute and capture the output (stdout and stderr) without inheriting your terminal.
	cmd_output =
		Cmd.new("echo")
			.args(["Hi"])
			.exec_output!()?

	Stdout.line!("${Str.inspect(cmd_output)}")?

	# To run a command with environment variables.
	Cmd.new("env")
		.clear_envs() # You probably don't need to clear all other environment variables, this is just an example.
		.env("FOO", "BAR")
		.envs([("BAZ", "DUCK"), ("XYZ", "ABC")]) # Set multiple environment variables at once with `envs`
		.exec_cmd!()?

	# To execute and just get the exit code (prints to your terminal).
	# Prefer using `exec!` or `exec_cmd!`.
	exit_code =
		Cmd.new("cat")
			.args(["non_existent.txt"])
			.exec_exit_code!()?

	Stdout.line!("Exit code: ${exit_code.to_str()}")?

	# To execute and capture the output (stdout and stderr) in the original form as bytes without inheriting your terminal.
	# Prefer using `exec_output!`.
	cmd_output_bytes =
		Cmd.new("echo")
			.args(["Hi"])
			.exec_output_bytes!()?

	Stdout.line!("${Str.inspect(cmd_output_bytes)}")?

	Ok({})
}

Output

Run this from the directory that has main.roc in it:

$ roc main.roc
Hello
{ stderr_utf8_lossy: "", stdout_utf8: "Hi
" }
BAZ=DUCK
FOO=BAR
XYZ=ABC
cat: non_existent.txt: No such file or directory
Exit code: 1
{ stderr_bytes: [], stdout_bytes: [72, 105, 10] }