cmd

Macro cmd 

Source
cmd!() { /* proc-macro */ }
Expand description

Generates a command expression by combining static strings, conditional logic, loops, pattern matching, and closures to dynamically build and format command-line arguments.

The cmd! macro supports flexible syntax constructs such as:

  • Static arguments: Basic string arguments.
  • Conditional inclusion: Using if or if let to conditionally include arguments.
  • Iterative inclusion: Using for loops to include multiple arguments from collections.
  • Pattern matching: Using match expressions for dynamic argument selection.
  • Closures: Dynamically generating arguments at runtime.

§Examples

§Basic Usage

let command = cmd!("echo", "test");
assert_eq!(format!("{command:?}"), r#""echo" "test""#.to_string());

§Current Directory

let command = cmd!(
    cd "~/";
    "echo",
    "test",
);

assert_eq!(format!("{command:?}"), r#"cd "~/" && "echo" "test""#);

§Environment Vars

const NEW_VAR: &str = "NEW_VAR";

let command = cmd!(
    env {
        "TEST": "test",
        NEW_VAR: "new_var"
    };
    "echo",
    "test",
);

assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#);
§Conditional

You can have a default value set for an environment variable.

const NEW_VAR: &str = "NEW_VAR";
std::env::set_var("TEST", "realvalue");

let command = cmd!(
    env {
        "TEST":? "test",
        NEW_VAR: "new_var"
    };
    "echo",
    "test",
);

assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" "echo" "test""#);

§Current Directory and Environment Variable Order

let command = cmd!(
    cd "~/";
    env {
        "TEST": "test",
    };
    "echo",
    "test",
);

assert_eq!(
    format!("{command:?}"),
    r#"cd "~/" && TEST="test" "echo" "test""#
);

§Conditional Arguments

let include_arg = true;

let command = cmd!("echo", "test", if include_arg => "optional_arg");
assert_eq!(format!("{command:?}"), r#""echo" "test" "optional_arg""#.to_string());

§Conditional Pattern Matching

let single_option = Some("single");
let multi_option: Option<&str> = None;

let command = cmd!(
    "echo",
    "test",
    if let Some(arg) = single_option => arg,
    if let Some(arg) = multi_option => [
        "multi",
        arg,
    ],
);
assert_eq!(format!("{command:?}"), r#""echo" "test" "single""#.to_string());

§Iterative Argument Inclusion

let args = &["arg1", "arg2"];

let command = cmd!("echo", for args);
assert_eq!(format!("{command:?}"), r#""echo" "arg1" "arg2""#.to_string());

§Iteration with for in

let single_iter = &["arg1", "arg2"];
let multi_iter = &["multi1", "multi2"];

let command = cmd!(
    "echo",
    "test",
    for arg in single_iter => arg,
    for arg in multi_iter => [
        "multi",
        arg,
    ],
);
assert_eq!(format!("{command:?}"), r#""echo" "test" "arg1" "arg2" "multi" "multi1" "multi" "multi2""#.to_string());

§Match Statements

enum TestArgs {
    Arg1,
    Arg2,
    Arg3,
}

let match_arg = TestArgs::Arg2;
let command = cmd!(
    "echo",
    "test",
    match match_arg {
        TestArgs::Arg1 => "arg1",
        TestArgs::Arg2 => ["arg1", "arg2"],
        TestArgs::Arg3 => ["arg1", "arg2", "arg3"],
    }
);
assert_eq!(format!("{command:?}"), r#""echo" "test" "arg1" "arg2""#.to_string());

§Dynamic Closures

let numbers = vec![1, 2, 3];
let multiplier = 2;

let command = cmd!("echo", || numbers.into_iter().map(|n| format!("{}", n * multiplier)));
assert_eq!(format!("{command:?}"), r#""echo" "2" "4" "6""#.to_string());