using System;
class cmdline {
static void Main (string[] arg) {
Console.WriteLine (System.AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine ($"{arg.Length} parámetros");
for (int i = 0; i < arg.Length; i++)
Console.WriteLine ($"Parámetro {i} -> {arg[i]}");
if (arg.Length != 1) {
Console.WriteLine ("Solo un parámetro por favor");
return;
}
Console.WriteLine ($"Hola {arg[0]}");
}
}
C# nos ofrece exactamente el mismo interfaz que Java. Los parámetros
se pasan en una matriz de cadenas de caracteres al método llamado
Main de la clase principal del programa.
La matriz de parámetros solo contiene los parámetros y no el nombre del programa como primer elemento tal y como hemos visto en otros lenguajes.
El nombre del ejecutable se almacena en:
System.AppDomain.CurrentDomain.FriendlyNameAlternativamente podemos acceder a los arguments tal y como los recibimos en los programas C/C++, ejecutando el siguiente método:
Environment.GetCommandLineArgs()
Como ya podemos esperar, existen varios paquetes con los que procesar los argumentos de forma más fácil y potente. Al igual que me ha sucedido con Rust, hacer que los módulos funcionen ha sido bastante frustrante, al menos en una Debian 12 estándar usando mono.
Al parecer la forma más segura de evitar este tipo de problemas es usar el entorno
dotnetproporcionado por Microsoft.
Entre las posibles opciones decidí utilizar el paquete
Options que ofrece una funcionalidad muy similar a
getopts, el cual conocemos muy bien a estas alturas. Al
parecer existía un paquete en Debian llamado
libmono-options-cil, pero parece que ya no está disponible,
así que la mejor opción para poder usar este paquete, es descargar las
fuentes directamente del repositorio de mono, usando el
siguiente comando.
wget httpx://raw.githubusercontent.com/mono/mono/refs/heads/main/mcs/class/Mono.Options/Mono.Options/Options.cs
Ahora que disponemos del módulo para procesar los parámetros, podemos escribir nuestro programa, el cual, estoy seguro, que os resultará familiar.
using System;
using System.Collections.Generic;
using Mono.Options;
class Program
{
static void Main(string[] args)
{
bool showHelp = false;
string inputFile = "input.txt";
string outputFile = "output.txt";
var options = new OptionSet
{
{ "h|help", "show this message and exit", h => showHelp = (h != null) },
{ "i|input=", "input file (default: input.txt)", i => inputFile = i },
{ "o|output=", "output file (default: output.txt)", o => outputFile = o },
};
List<string> extraArgs;
try
{
extraArgs = options.Parse(args);
}
catch (OptionException e)
{
Console.WriteLine(e.Message);
Console.WriteLine("Try `--help` for more information.");
return;
}
if (showHelp)
{
Console.WriteLine("Usage: app [OPTIONS]");
Console.WriteLine();
Console.WriteLine("Options:");
options.WriteOptionDescriptions(Console.Out);
return;
}
Console.WriteLine($"Input file : {inputFile}");
Console.WriteLine($"Output file: {outputFile}");
}
}El módulo utiliza la clase OptionSet para definir los
flags que esperamos procesar. Como podéis ver, podemos definir flags
cortos así como indicar si esperamos parámetros obligatorios (añadiendo
= tras el nombre del flag) u opcionales (añadiendo
: tras el nombre del flag).
El último campo de los elementos OptionSet es una
función. En este caso, para hacer el código más pequeño hemos utilizado
expresiones lambda. Para cada posible opción inicializamos las variables
que necesitamos y poco más.
Aunque ya hablaremos las funciones lambda cuando hablemos de funciones, para poder entender el programa. La expresión:
i => inputFile = iEs equivalente a una función que recibe un parámetro llamado
iy asigna su valor a la variableinputFile.static void SetInput(string o) { inputFile = o; }En este caso, dejando a un lado, los cambios necesarios para poder modificar
inputFiledesde la función (lo más fácil es hacer todas las variables y funcionesstatic, la declaración delOptionSetcorrespondiente sería:{ "i|input=", "input file (default: input.txt)", SetInput},
El parseado de los parámetros lo realiza el método
Parse, el cual procesará la entrada según lo que hayamos
especificado en nuestro OptionSet y producirá una excepción
si encuentra cualquier error. Además, Parse nos devuelve
cualquier parámetro adicional, no incluido en el OptionSet
que encuentre. Útil para utilidades que esperan varios nombres de
ficheros por ejemplo.
Resumen
- C# recibe los argumentos de la línea de comandos como un array de cadenas
- C# no incluye el nombre del programa en el primer elemento del array de argumentos
- El paquete
Optionnos permite procesar los argumentos de forma sencilla y muy similar a como lo hace el paquetegetoptestándar.
■
