#shell #process #command #macro #dsl #scripting-language

command-macros

Macros for creating std::process::Command with shell-like syntax

19 releases

Uses old Rust 2015

0.2.9 Jun 8, 2021
0.2.7 Sep 17, 2019
0.2.6 Oct 9, 2018
0.2.4 Jul 22, 2018
0.1.5 Jul 29, 2016

#474 in Rust patterns

Download history 76/week @ 2024-07-19 161/week @ 2024-07-26 40/week @ 2024-08-02 40/week @ 2024-08-09 20/week @ 2024-08-16 19/week @ 2024-08-23 25/week @ 2024-08-30 23/week @ 2024-09-06 52/week @ 2024-09-13 39/week @ 2024-09-20 25/week @ 2024-09-27 26/week @ 2024-10-04 31/week @ 2024-10-11 17/week @ 2024-10-18 12/week @ 2024-10-25 23/week @ 2024-11-01

87 downloads per month
Used in 7 crates

MIT license

21KB
238 lines

command-macros

documentation, crate

Macros for creating std::process::Command with shell-like syntax. Created to make using Rust as a scripting language more pleasant.

This crate contains two macros, command!() – fully-featured, but requires nightly, and a simpler cmd!(), built by macro_rules.

command!

Build Status

Installation

This macro requires nightly Rust and enabling a "nightly" feature. Put the following in your Cargo.toml.

[dependencies.command-macros]
version = "0.2.9"
features = ["nightly"]

And then add on top of your root module:

#![feature(proc_macro_hygiene)]

extern crate command_macros;

use command_macros::command;

If you're not running the latest nightly, try the following versions:

nightly date command-macros version
2020-05-20 — 0.2.9
2018-10-06 — 2021-06-05 0.2.7
2018-10-06 — 2019-08-27 0.2.6
2018-10-04 — 2018-10-05 0.2.5
2018-07-17 — 2018-10-03 0.2.4
2018-05-17 — 2018-07-16 0.2.3
2018-04-07 — 2018-05-16 0.2.2

Examples

command!(
    ffmpeg -i (file)
    -c:v libx264 -preset (preset) [moreargs]
    -c:a copy
    file:(tmpname)
).status().unwrap();

should be roughly equivalent to running

std::process::Command::new("ffmpeg")
    .args(&["-i", &file])
    .args(&["-c:v", "libx264", "-preset", &preset])
    .args(moreargs)
    .args(&["-c:a", "copy"])
    .arg(&format!("file:{}", tmpname))
    .status()
    .unwrap();

As you see, you use (expr) to create an argument (or a part of it) from arbitrary Rust expression and [expr] for multiple arguments. The & is added automatically, similarly to how print! works.

Moreover, command! will handle file and tmpname being OsStr correctly, while the manual version would require some modifications.

Additionally, you can use if, if let, match and for. This snippet also showcases (( expr )) feature.

command!(make
    if let Some(n) = n_cores { -j ((n + 1)) }
).status().unwrap();

Both macros return Command by value, so you can store them in a variable for later:

let cmd = command!(mkv --fs);

If you have partially prepared command (Command or &mut Command), you can also pass it to this macro:

let base: Command = prepare();
let cmd = command!({base} install (package));

cmd!

Installation

Put the following in your Cargo.toml.

[dependencies]
command-macros = "0.2"

And then add on top of your root module:

#[macro_use] extern crate command_macros;

Limitations

This macro is a "lite" version of the command!. Differences:

  • Worse error messages.
  • It is whitespace-insensitive.
  • Creating arguments from arbitrary tokens (such as -c:a) is not supported (only idents). The workaround is to use Rust string as an expression: ("-c:a").
  • ((expr)) and (expr) always evaluate to full argument (no tricks like file:(filename)).
  • Expressions in if, match and for have to be surrounded by parens.
  • No support for else if (use else { if ... } instead).

Besides, all other features should work.

Examples

Examples from command! section rewritten to match cmd! syntax:

command!(
    ffmpeg ("-i") (file)
    ("-c:v") libx264 ("-preset") (preset) [moreargs]
    ("-c:a") copy
    (format!("file:{}", tmpname))
).status().unwrap();
command!(make
    if let Some(n) = (n_cores) { ("-j") ((n + 1)) }
).status().unwrap();

Changelog

Dependencies

~70KB