Aceptando Argumentos de Línea de Comandos

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Bienvenido a Aceptando Argumentos de Línea de Comandos. Esta práctica es parte del Rust Book. Puedes practicar tus habilidades de Rust en LabEx.

En esta práctica, crearemos un nuevo proyecto llamado "minigrep" que acepte dos argumentos de línea de comandos: una cadena de texto a buscar y una ruta de archivo.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-100418{{"Aceptando Argumentos de Línea de Comandos"}} rust/function_syntax -.-> lab-100418{{"Aceptando Argumentos de Línea de Comandos"}} rust/expressions_statements -.-> lab-100418{{"Aceptando Argumentos de Línea de Comandos"}} rust/method_syntax -.-> lab-100418{{"Aceptando Argumentos de Línea de Comandos"}} rust/operator_overloading -.-> lab-100418{{"Aceptando Argumentos de Línea de Comandos"}} end

Aceptando Argumentos de Línea de Comandos

Vamos a crear un nuevo proyecto, como siempre, con cargo new. Llamaremos a nuestro proyecto minigrep para diferenciarlo de la herramienta grep que puede que ya tengas en tu sistema.

$ cargo new minigrep
     Created binary (application) `minigrep` project
$ cd minigrep

La primera tarea es hacer que minigrep acepte sus dos argumentos de línea de comandos: la ruta del archivo y una cadena de texto a buscar. Es decir, queremos poder ejecutar nuestro programa con cargo run, dos guiones para indicar que los siguientes argumentos son para nuestro programa y no para cargo, una cadena de texto a buscar y una ruta a un archivo en el que buscar, así:

cargo run -- searchstring example-filename.txt

En este momento, el programa generado por cargo new no puede procesar los argumentos que le damos. Algunas bibliotecas existentes en https://crates.io pueden ayudar a escribir un programa que acepte argumentos de línea de comandos, pero como estás aprendiendo este concepto, vamos a implementar esta capacidad nosotros mismos.

Leyendo los Valores de los Argumentos

Para permitir que minigrep lea los valores de los argumentos de línea de comandos que le pasamos, necesitaremos la función std::env::args proporcionada en la biblioteca estándar de Rust. Esta función devuelve un iterador de los argumentos de línea de comandos pasados a minigrep. Cubriremos los iteradores en detalle en el Capítulo 13. Por ahora, solo necesitas saber dos detalles sobre los iteradores: los iteradores producen una serie de valores, y podemos llamar al método collect en un iterador para convertirlo en una colección, como un vector, que contiene todos los elementos que produce el iterador.

El código de la Lista 12-1 permite que tu programa minigrep lea cualquier argumento de línea de comandos pasado a él, y luego recopile los valores en un vector.

Nombre del archivo: src/main.rs

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    dbg!(args);
}

Lista 12-1: Recopilando los argumentos de línea de comandos en un vector y mostrándolos

Primero traemos el módulo std::env al ámbito con una declaración use para poder usar su función args. Observe que la función std::env::args está anidada en dos niveles de módulos. Como discutimos en el Capítulo 7, en casos donde la función deseada está anidada en más de un módulo, hemos elegido traer el módulo padre al ámbito en lugar de la función. Al hacerlo, podemos usar fácilmente otras funciones de std::env. También es menos ambiguo que agregar use std::env::args y luego llamar a la función solo con args, porque args podría fácilmente ser confundido con una función que está definida en el módulo actual.

La función args y el Unicode no válido

Tenga en cuenta que std::env::args se interrumpirá si algún argumento contiene Unicode no válido. Si su programa necesita aceptar argumentos que contengan Unicode no válido, use std::env::args_os en su lugar. Esa función devuelve un iterador que produce valores OsString en lugar de valores String. Hemos elegido usar std::env::args aquí por simplicidad porque los valores OsString difieren según la plataforma y son más complejos de trabajar que los valores String.

En la primera línea de main, llamamos a env::args, y inmediatamente usamos collect para convertir el iterador en un vector que contiene todos los valores producidos por el iterador. Podemos usar la función collect para crear muchos tipos de colecciones, por lo que anotamos explícitamente el tipo de args para especificar que queremos un vector de cadenas. Aunque rara vez necesites anotar tipos en Rust, collect es una función que a menudo necesitas anotar porque Rust no puede inferir el tipo de colección que quieres.

Finalmente, imprimimos el vector usando la macro de depuración. Intentemos ejecutar el código primero sin argumentos y luego con dos argumentos:

$ cargo run
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
]
$ cargo run -- needle haystack
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
"needle",
"haystack",
]

Observe que el primer valor en el vector es "target/debug/minigrep", que es el nombre de nuestro binario. Esto coincide con el comportamiento de la lista de argumentos en C, permitiendo que los programas usen el nombre con el que se invocaron en su ejecución. A menudo es conveniente tener acceso al nombre del programa en caso de que desees imprimirlo en mensajes o cambiar el comportamiento del programa según el alias de línea de comandos que se usó para invocar el programa. Pero con fines de este capítulo, lo ignoraremos y guardaremos solo los dos argumentos que necesitamos.

Guardando los Valores de los Argumentos en Variables

El programa actualmente es capaz de acceder a los valores especificados como argumentos de línea de comandos. Ahora necesitamos guardar los valores de los dos argumentos en variables para poder usar los valores en el resto del programa. Hacemos eso en la Lista 12-2.

Nombre del archivo: src/main.rs

use std::env;

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

    let query = &args[1];
    let file_path = &args[2];

    println!("Searching for {}", query);
    println!("In file {}", file_path);
}

Lista 12-2: Creando variables para almacenar el argumento de consulta y el argumento de ruta de archivo

Como vimos cuando imprimimos el vector, el nombre del programa ocupa el primer valor en el vector en args[0], por lo que comenzamos a tomar argumentos a partir del índice 1. El primer argumento que minigrep toma es la cadena que estamos buscando, por lo que ponemos una referencia al primer argumento en la variable query. El segundo argumento será la ruta del archivo, por lo que ponemos una referencia al segundo argumento en la variable file_path.

Imprimimos temporalmente los valores de estas variables para probar que el código está funcionando como esperamos. Vamos a ejecutar este programa nuevamente con los argumentos test y sample.txt:

$ cargo run -- test sample.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt

Excelente, el programa está funcionando! Los valores de los argumentos que necesitamos se están guardando en las variables correctas. Más adelante agregaremos algún manejo de errores para manejar ciertas situaciones potencialmente erróneas, como cuando el usuario no proporciona ningún argumento; por ahora, ignoraremos esa situación y trabajaremos en agregar capacidades de lectura de archivos en su lugar.

Resumen

¡Felicidades! Has completado la práctica de Aceptando Argumentos de Línea de Comandos. Puedes practicar más prácticas en LabEx para mejorar tus habilidades.