El tutorial de Rust no explica cómo tomar parámetros de la línea de comando. fn main()
solo se muestra con una lista de parámetros vacía en todos los ejemplos.
¿Cuál es la forma correcta de acceder a los parámetros de la línea de comandos main
?
El tutorial de Rust no explica cómo tomar parámetros de la línea de comando. fn main()
solo se muestra con una lista de parámetros vacía en todos los ejemplos.
¿Cuál es la forma correcta de acceder a los parámetros de la línea de comandos main
?
Respuestas:
Puede acceder a los argumentos de la línea de comandos utilizando las funciones std::env::args
o std::env::args_os
. Ambas funciones devuelven un iterador sobre los argumentos. El primero itera sobre String
s (que es fácil trabajar con él) pero entra en pánico si uno de los argumentos no es válido unicode. Este último itera sobre OsString
sy nunca se asusta.
Tenga en cuenta que el primer elemento del iterador es el nombre del programa en sí (esta es una convención en todos los sistemas operativos principales), por lo que el primer argumento es en realidad el segundo elemento iterado.
Una manera fácil de lidiar con el resultado de args
es convertirlo a Vec
:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}
Puede usar toda la caja de herramientas de iterador estándar para trabajar con estos argumentos. Por ejemplo, para recuperar solo el primer argumento:
use std::env;
fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Puede encontrar bibliotecas en crates.io para analizar los argumentos de la línea de comandos:
Docopt también está disponible para Rust, que genera un analizador para usted a partir de una cadena de uso. Como beneficio adicional en Rust, se puede usar una macro para generar automáticamente la estructura y hacer decodificación basada en tipo:
docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
Y puedes obtener los argumentos con:
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
El archivo README y la documentación tienen muchos ejemplos de trabajo completos.
Descargo de responsabilidad: soy uno de los autores de esta biblioteca.
Rust tiene un getopt
estilo de argumento CLI analizando en la caja de getopts .
Para mí, los getopts siempre se sentían demasiado bajos y docopt.rs era demasiada magia. Quiero algo explícito y directo que todavía proporcione todas las características si las necesito.
Aquí es donde los aplausos son útiles.
Se siente un poco como argparse de Python. Aquí hay un ejemplo de cómo se ve:
let matches = App::new("myapp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(Arg::with_name("CONFIG")
.short("c")
.long("config")
.help("Sets a custom config file")
.takes_value(true))
.arg(Arg::with_name("INPUT")
.help("Sets the input file to use")
.required(true)
.index(1))
.arg(Arg::with_name("debug")
.short("d")
.multiple(true)
.help("Sets the level of debugging information"))
.get_matches();
Puede acceder a sus parámetros así:
println!("Using input file: {}", matches.value_of("INPUT").unwrap());
// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);
(Copiado de la documentación oficial )
A partir de la versión 0.8 / 0.9, la ruta correcta a la función args () sería ::std::os::args
, es decir:
fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
Parece que Rust todavía es bastante volátil en este momento, incluso con E / S estándar, por lo que puede desactualizarse con bastante rapidez.
El óxido cambió de nuevo. os::args()
está en desuso a favor de std::args()
. Pero std::args()
no es una matriz, devuelve un iterador . Puede iterar sobre los argumentos de la línea de comandos, pero no puede acceder a ellos con subíndices.
http://doc.rust-lang.org/std/env/fn.args.html
Si desea los argumentos de la línea de comando como un vector de cadenas, esto funcionará ahora:
use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Rust: aprende a abrazar el dolor del cambio.
env::args().collect()
.
lo que @barjak dijo funciona para cadenas, pero si necesita el argumento como un número (en este caso, un uint), debe convertirlo así:
fn main() {
let arg : ~[~str] = os::args();
match uint::from_str(arg[1]){
Some(x)=>io::println(fmt!("%u",someFunction(x))),
None=>io::println("I need a real number")
}
}
También echa un vistazo a structopt:
extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
/// A flag, true if used in the command line.
#[structopt(short = "d", long = "debug", help = "Activate debug mode")]
debug: bool,
/// An argument of type float, with a default value.
#[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
speed: f64,
/// Needed parameter, the first on the command line.
#[structopt(help = "Input file")]
input: String,
/// An optional parameter, will be `None` if not present on the
/// command line.
#[structopt(help = "Output file, stdout if not present")]
output: Option<String>,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
A partir de las versiones más recientes de Rust (Rust> 0.10 / 11), la sintaxis de la matriz no funcionará. Tendrá que usar el método get.
[Editar] La sintaxis de la matriz funciona (de nuevo) en la noche. Por lo tanto, puede elegir entre el getter o el índice de matriz.
use std::os;
fn main() {
let args = os::args();
println!("{}", args.get(1));
}
// Compile
rustc args.rs && ./args hello-world // returns hello-world
Vec
s. Supongo que está allí durante un mes más o menos. Ver este ejemplo .
Rust ha evolucionado desde la respuesta de Calvin de mayo de 2013. Ahora uno analizaría los argumentos de la línea de comandos con as_slice()
:
use std::os;
fn seen_arg(x: uint)
{
println!("you passed me {}", x);
}
fn main() {
let args = os::args();
let args = args.as_slice();
let nitems = {
if args.len() == 2 {
from_str::<uint>(args[1].as_slice()).unwrap()
} else {
10000
}
};
seen_arg(nitems);
}
as_slice()
ya no existe y &args
debería usarse en su lugar.
El capítulo del libro Rust "No stdlib" cubre cómo acceder a los parámetros de las líneas de comando (otra forma).
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
Ahora, el ejemplo también tiene #![no_std]
lo que creo que significa que normalmente, la biblioteca estándar tendría el verdadero punto de entrada para su binario y llamaría a una función global llamada main()
. Otra opción es 'deshabilitar la main
cuña' con #![no_main]
. Lo que si no me equivoco es decirle al compilador que está tomando el control total sobre cómo se inicia su programa.
#![no_std]
#![no_main]
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: isize, argv: *const *const u8) -> isize {
0
}
No creo que esta sea una 'buena' forma de hacer las cosas si todo lo que quieres hacer es leer los argumentos de la línea de comandos. El std::os
módulo mencionado en otras respuestas parece ser una forma mucho mejor de hacer las cosas. Publico esta respuesta para completarla.
println(args[0])