Flecks of Rust #3: Returning an exit code to the shell

When you're writing command-line tools, you need to be a good citizen and return an error code to the shell that has invoked your program. This way shell scripts can determine if they can continue execution or if they should abort and report an error.

The main() function in a Rust program doesn't return a value to the shell, but you can set the exit code with std::process::exit, as detailed in the documentation.

Here is a small example that builds on the example found in the documentation. It returns an exit code of 0 if all is well, and 1 if there were no command line arguments supplied.

use std::env;

fn run_app(args: &[String]) -> Result<(), &'static str> {
    if args.len() < 1 {
        Err("missing command line argument")
    else {
        println!("{}", args[0]);


fn main() {
    let args: Vec = env::args().collect();

    std::process::exit(match run_app(&args[1..]) {
        Ok(_) => 0,
        Err(err) => {
            eprintln!("error: {:?}", err);

The main function passed all the command line arguments except the first (which is the name of the program) to the run_app function. That function returns a Result with an empty type of all is well, or a static string with an error message in case of error.

The exit code set by std::process::exit is determined from the result returned by the run_app function using a match expression.

If the program is invoked with no command line arguments, an error message is printed in the shell, and the error code is 1:

% cargo run --quiet
error: "missing command line argument"
% echo $?

But if you run the program with a command line argument, it will echo back the argument you gave and set the return code to zero:

% cargo run --quiet -- hello
% echo $?

Note that if you give command line arguments to Cargo when you run your program, you need to separate the arguments intended for your own program with --.

Hope you find this useful in your command line tool projects.