Crate command_macros [−] [src]
Macros for creating
std::process::Command
with shell-like syntax.
The command!
macro is a syntax extension and requires nightly,
the cmd!
is simpler version built using macro_rules!
.
This page describes syntax used by both command!
and cmd!
macros.
See the github page for more general introduction.
Features marked with * are unavailable for cmd!
.
Naked idents
First ident is treated as command name, the rest are parsed as arugments. This invocation:
cmd!(echo foo bar).status().unwrap();
expands to
{ let cmd = ::std::process::Command::new("echo"); cmd.arg("foo"); cmd.arg("bar"); cmd }.status().unwrap()
(expression)
(OsStr expression)
Interior of ( )
is parsed as Rust expression
which should evaluate to T: AsRef<OsStr>
.
This will be put in cmd.arg(& $expr)
.
The &
is added automatically, like in println!
,
to prevent accidentally moving arguments.
let filename = String::new("foo bar"); let get_command = || "touch"; cmd!( (get_command()) (filename) ).status().unwrap();
((expression))
(ToString expression)
Interior of (( ))
is parsed as Rust expression
which should evaluate to T: ToString
.
Similar rules as with ( )
apply.
The following should echo 4
cmd!( echo ((2+2)) ).status().unwrap();
[expression]
(args expression)
Interior of [ ]
is parsed as Rust expression
which should evaluate to [T: AsRef<OsStr>]
(modulo Deref
).
This expression will be put in cmd.args(& $expr)
let args: Vec<_> = std::env::args_os().collect(); cmd!( (args[1]) [args[2..]] ).status().unwrap();
{expression}
(Command expression)
Interior of { }
is parsed as Rust expression
which should evaluate to Command
or &mut Command
(or anything that has arg
and args
methods).
It is allowed only at the beginning of macro.
It is helpful when you want to append arguments to
existing command:
let cmd = ::std::process::Command::new("echo"); cmd!( {&mut cmd} bar baz )
Strings*
String literals work like in shell – they expand to single argument or part of it.
Character literals and raw string literals are also supported.
Note that shell-style "$variables"
won't work here.
command!("echo" "single argument" "***")
cmd!
workaroud:
cmd!(echo ("single argument") ("***"))
Arbitrary tokens*
Everything that is not [block], {block}, (block) or string literal,
will be stringified. This is mostly helpful for unix-like flags.
Everything within a single whitespace-separated chunk will be treated
as a single argument. In the following example we are passing
three arguments to a foo.2.5
command.
command!(foo.2.5 --flag -v:c -=|.|=-).status().unwrap();
cmd!
workaround: ("--flag")
.
(-flags)
When your flag contains only -+=,.;:
and idents, you can omit the quotes. The flag has to start
with -
or +
.
This is only necessary for cmd!
,
when using command!
, it will generate warning,
as you can just remove the surrounding parens.
So instead
cmd!(foo ("--bar=baz"))
you can write
cmd!(foo (--bar=baz)
Please note that all whitespace will be ignored.
Multi-part arguments*
You can mix ((e))
, (e)
, tokens and strings within a single
arguments as long as they are not separated by whitespace.
The following will touch the foo.v5.special edition
file.
let p = Path::new("foo"); let version = 5; command!(touch (p).v((version))".special edition")
This is roughly equivalent to (format!(...))
, but the macro version
can handle OsStr
s (such as Path
).
Please note that this is not supported by cmd!
, which would evaluate
every part as separate argument.
{}
*
Empty {}
is treated as "{}"
. This is handy when using commands like find
.
There has to be no space between braces.
If
The if
token should be surrounded by whitespace.
The expression (and pattern in if-let) is parsed as Rust,
the inside of {block} is parsed using regular commmand!
syntax
and can evaluate to multiple arguments (or 0).
The following should pass --number
5
to command foo
.
let bar = 5; let option = Some(5); command!(foo if bar > 10 { zzz } else if let Some(a) = option { --number ((a)) } ).status().unwrap();
cmd!
limitations: else if
is not supported, expression has to be in parens.
cmd!(foo if (bar > 10) { zzz } else { if let Some(a) = (option) { ("--number") ((a)) } } ).status().unwrap();
Match
The match
token should be surrounded by whitespace.
The expression and patterns are parsed as Rust.
On the right side of =>
there should be a {block},
which will be parsed (similarly to if blocks)
using regular command!
syntax.
This example will pass a single argument yes
to foo
command.
let option = Some(5); command!(foo match option { Some(x) if x > 10 => {} _ => { yes } } ).status().unwrap()
cmd!
limitation: expression after match
has to be in parens.
For
The for
token should be surrounded by whitespace.
The expression and patterns are parsed as Rust.
The interior of block is parsed using command!
syntax,
and will be evaluated in every iteration.
This example will pass three arguments 1
2
3
.
command!(echo for x in 1..4 { ((x)) } ).status().unwrap()
Macros
cmd! |
Simple macro for creating |
command! |
Full-featured macro for creating |
Functions
plugin_registrar |