web-dev-qa-db-fra.com

Meilleur moyen d’analyser les arguments de ligne de commande en C #?

Lors de la création d'applications console prenant des paramètres, vous pouvez utiliser les arguments passés à Main(string[] args).

Dans le passé, j'ai simplement indexé/bouclé ce tableau et effectué quelques expressions régulières pour extraire les valeurs. Cependant, lorsque les commandes deviennent plus compliquées, l'analyse peut devenir assez laide.

Donc je suis intéressé par:

  • Bibliothèques que vous utilisez
  • Les motifs que vous utilisez

Supposons que les commandes respectent toujours les normes communes telles que répondu ici .

733
Paul Stovell

Je suggère fortement d'utiliser NDesk.Options ( Documentation ) et/ou Mono.Options (même API, espace de noms différent). Un exemple tiré de la documentation :

bool show_help = false;
List<string> names = new List<string> ();
int repeat = 1;

var p = new OptionSet () {
    { "n|name=", "the {NAME} of someone to greet.",
       v => names.Add (v) },
    { "r|repeat=", 
       "the number of {TIMES} to repeat the greeting.\n" + 
          "this must be an integer.",
        (int v) => repeat = v },
    { "v", "increase debug message verbosity",
       v => { if (v != null) ++verbosity; } },
    { "h|help",  "show this message and exit", 
       v => show_help = v != null },
};

List<string> extra;
try {
    extra = p.Parse (args);
}
catch (OptionException e) {
    Console.Write ("greet: ");
    Console.WriteLine (e.Message);
    Console.WriteLine ("Try `greet --help' for more information.");
    return;
}
324
jonp

J'aime beaucoup la bibliothèque d'analyseurs de ligne de commande ( http://commandline.codeplex.com/ ). Il offre un moyen très simple et élégant de définir des paramètres via des attributs:

class Options
{
    [Option("i", "input", Required = true, HelpText = "Input file to read.")]
    public string InputFile { get; set; }

    [Option(null, "length", HelpText = "The maximum number of bytes to process.")]
    public int MaximumLenght { get; set; }

    [Option("v", null, HelpText = "Print details during execution.")]
    public bool Verbose { get; set; }

    [HelpOption(HelpText = "Display this help screen.")]
    public string GetUsage()
    {
        var usage = new StringBuilder();
        usage.AppendLine("Quickstart Application 1.0");
        usage.AppendLine("Read user manual for usage instructions...");
        return usage.ToString();
    }
}
198
Adrian Grigore

La bibliothèque WPF TestApi est fournie avec l'un des analyseurs syntaxiques en ligne de commande les plus agréables pour le développement en C #. Je recommande vivement de regarder à partir de le blog d'Ivo Manolov sur l'API :

// EXAMPLE #2:
// Sample for parsing the following command-line:
// Test.exe /verbose /runId=10
// This sample declares a class in which the strongly-
// typed arguments are populated
public class CommandLineArguments
{
   bool? Verbose { get; set; }
   int? RunId { get; set; }
}

CommandLineArguments a = new CommandLineArguments();
CommandLineParser.ParseArguments(args, a);
50
user7116
24
abatishchev

On dirait que tout le monde a son propre analyseur syntaxique en ligne de commande pour les animaux de compagnie. J'imagine qu'il vaut mieux ajouter le mien également :).

http://bizark.codeplex.com/

Cette bibliothèque contient un analyseur de ligne de commande qui initialisera une classe avec les valeurs de la ligne de commande. Il a une tonne de fonctionnalités (je l'ai construit depuis de nombreuses années).

De la documentation ...

L'analyse de ligne de commande dans l'infrastructure BizArk présente les fonctionnalités clés suivantes:

  • Initialisation automatique: Les propriétés de la classe sont automatiquement définies en fonction des arguments de la ligne de commande.
  • Propriétés par défaut: Envoie une valeur sans spécifier le nom de la propriété.
  • Conversion de valeur: Utilise la puissante classe ConvertEx également incluse dans BizArk pour convertir les valeurs en un type approprié.
  • Indicateurs booléens: Les indicateurs peuvent être spécifiés simplement en utilisant l'argument (ex,/b pour true et/b- pour false) ou en ajoutant la valeur true/faux, oui/non, etc.
  • Tableaux d'arguments: Ajoutez simplement plusieurs valeurs après le nom de la ligne de commande pour définir une propriété définie comme un tableau. Ex,/x 1 2 3 va peupler x avec le tableau {1, 2, 3} (en supposant que x est défini comme un tableau d’entiers).
  • Alias ​​de ligne de commande: Une propriété peut prendre en charge plusieurs alias de ligne de commande. Par exemple, l’aide utilise l’alias?.
  • Reconnaissance partielle du nom: Il n’est pas nécessaire d’épeler le nom complet ou un alias, il suffit d’épeler suffisamment pour que l’analyseur puisse distinguer la propriété/alias du autres.
  • Prend en charge ClickOnce: Peut initialiser des propriétés même lorsqu'elles sont spécifiées en tant que chaîne de requête dans une URL pour les applications déployées ClickOnce. La méthode d’initialisation de la ligne de commande détectera si elle s’exécute en tant que ClickOnce ou non. Votre code n’a donc pas besoin d’être modifié pour pouvoir être utilisé.
  • Crée automatiquement /? help: Ceci inclut le formatage Nice qui prend en compte la largeur de la console.
  • Charger/Enregistrer des arguments de ligne de commande dans un fichier: Ceci est particulièrement utile si vous souhaitez disposer de plusieurs grands ensembles complexes d'arguments de ligne de commande. courir plusieurs fois.
14
Brian

J'ai écrit un analyseur d'arguments en ligne de commande C # il y a quelque temps. Son à: http://www.codeplex.com/CommandLineArguments

13
PeterH

CLAP (analyseur d'argument de ligne de commande) a une API utilisable et est merveilleusement documenté. Vous créez une méthode en annotant les paramètres. https://github.com/adrianaisemberg/CLAP

9
Colonel Panic

Il existe de nombreuses solutions à ce problème. Pour être complet et fournir l’alternative si quelqu'un le souhaite, j’ajoute cette réponse pour deux classes utiles dans mon bibliothèque de code Google .

Le premier est ArgumentList, qui n’est responsable que de l’analyse des paramètres de ligne de commande. Il collecte les paires nom-valeur définies par les commutateurs '/ x: y' ou '-x = y' et collecte également une liste d'entrées 'non nommées'. C'est basique l'utilisation est discutée ici , voir la classe ici .

La deuxième partie est CommandInterpreter , qui crée une application de ligne de commande entièrement fonctionnelle à partir de votre classe .Net. Par exemple:

using CSharpTest.Net.Commands;
static class Program
{
    static void Main(string[] args)
    {
        new CommandInterpreter(new Commands()).Run(args);
    }
    //example ‘Commands’ class:
    class Commands
    {
        public int SomeValue { get; set; }
        public void DoSomething(string svalue, int ivalue)
        { ... }

Avec l'exemple de code ci-dessus, vous pouvez exécuter ce qui suit:

Program.exe DoSomething "valeur de chaîne" 5

-- ou --

Program.exe dosomething/ivalue = 5 -svalue: "valeur de chaîne"

C'est aussi simple que cela ou aussi complexe que vous le souhaitez. Vous pouvez consulter le code source , afficher l'aide , ou télécharger le fichier binaire .

5
csharptest.net

Vous pouvez aimer mon un Rug.Cmd

Analyseur d'arguments en ligne de commande facile à utiliser et extensible. Poignées: Bool, Plus/Minus, String, Liste de chaînes, CSV, Énumération.

Construit en '/?' mode d'aide.

Construit en '/ ??' et '/? D' modes de génération de document.

static void Main(string[] args) 
{            
    // create the argument parser
    ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing");

    // create the argument for a string
    StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments");

    // add the argument to the parser 
    parser.Add("/", "String", StringArg);

    // parse arguemnts
    parser.Parse(args);

    // did the parser detect a /? argument 
    if (parser.HelpMode == false) 
    {
        // was the string argument defined 
        if (StringArg.Defined == true)
        {
            // write its value
            RC.WriteLine("String argument was defined");
            RC.WriteLine(StringArg.Value);
        }
    }
}

Edit: Ceci est mon projet et, en tant que tel, cette réponse ne doit pas être considérée comme une approbation d'une tierce partie. Cela dit, je l’utilise pour tous les programmes en ligne de commande que j’écris. C’est une source ouverte et j’espère que d’autres en bénéficieront.

4
Phill Tew

J'aime celui-là , car vous pouvez "définir des règles" pour les arguments, nécessaires ou non, ...

ou si vous êtes un gars sous Unix, vous aimerez peut-être le port GNU Getopt .NET .

4
Xn0vv3r

Il existe un analyseur d'argument de ligne de commande à l'adresse suivante: http://www.codeplex.com/commonlibrarynet

Il peut analyser les arguments en utilisant
1. les attributs
2. appels explicites
3. ligne unique de plusieurs arguments OR tableau de chaînes

Il peut gérer des choses comme celles-ci:

- config : Qa - date de début : $ { aujourd'hui } - région : "New York" Settings01

C'est très facile à utiliser.

3
jerome

C’est un gestionnaire que j’ai écrit à partir de la classe Novell Options.

Celui-ci est destiné aux applications console qui exécutent une boucle de style while (input !="exit"), une console interactive telle qu'une console FTP par exemple.

Exemple d'utilisation:

static void Main(string[] args)
{
    // Setup
    CommandHandler handler = new CommandHandler();
    CommandOptions options = new CommandOptions();

    // Add some commands. Use the v syntax for passing arguments
    options.Add("show", handler.Show)
        .Add("connect", v => handler.Connect(v))
        .Add("dir", handler.Dir);

    // Read lines
    System.Console.Write(">");
    string input = System.Console.ReadLine();

    while (input != "quit" && input != "exit")
    {
        if (input == "cls" || input == "clear")
        {
            System.Console.Clear();
        }
        else
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (options.Parse(input))
                {
                    System.Console.WriteLine(handler.OutputMessage);
                }
                else
                {
                    System.Console.WriteLine("I didn't understand that command");
                }

            }

        }

        System.Console.Write(">");
        input = System.Console.ReadLine();
    }
}

Et la source:

/// <summary>
/// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options).
/// </summary>
public class CommandOptions
{
    private Dictionary<string, Action<string[]>> _actions;
    private Dictionary<string, Action> _actionsNoParams;

    /// <summary>
    /// Initializes a new instance of the <see cref="CommandOptions"/> class.
    /// </summary>
    public CommandOptions()
    {
        _actions = new Dictionary<string, Action<string[]>>();
        _actionsNoParams = new Dictionary<string, Action>();
    }

    /// <summary>
    /// Adds a command option and an action to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action action)
    {
        _actionsNoParams.Add(name, action);
        return this;
    }

    /// <summary>
    /// Adds a command option and an action (with parameter) to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate that has one parameter - string[] args.</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action<string[]> action)
    {
        _actions.Add(name, action);
        return this;
    }

    /// <summary>
    /// Parses the text command and calls any actions associated with the command.
    /// </summary>
    /// <param name="command">The text command, e.g "show databases"</param>
    public bool Parse(string command)
    {
        if (command.IndexOf(" ") == -1)
        {
            // No params
            foreach (string key in _actionsNoParams.Keys)
            {
                if (command == key)
                {
                    _actionsNoParams[key].Invoke();
                    return true;
                }
            }
        }
        else
        {
            // Params
            foreach (string key in _actions.Keys)
            {
                if (command.StartsWith(key) && command.Length > key.Length)
                {

                    string options = command.Substring(key.Length);
                    options = options.Trim();
                    string[] parts = options.Split(' ');
                    _actions[key].Invoke(parts);
                    return true;
                }
            }
        }

        return false;
    }
}
2
Chris S

Je suis récemment tombé sur l'implémentation d'analyse syntaxique de la ligne de commande FubuCore qui me plait beaucoup, pour les raisons suivantes:

  • il est facile à utiliser - bien que je n'ai pas trouvé de documentation à ce sujet, la solution FubuCore fournit également un projet contenant un ensemble de tests unitaires de Nice qui en dit plus sur les fonctionnalités que n'importe quelle documentation.
  • il a une conception orientée objet de Nice, aucune répétition de code ou d'autres choses telles que j'avais l'habitude d'avoir dans ma ligne de commande analyser des applications
  • c'est déclaratif: vous écrivez en gros des classes pour les commandes et des ensembles de paramètres et vous les décorez avec des attributs pour définir diverses options (par exemple, nom, description, obligatoire/facultatif)
  • la bibliothèque imprime même un Nice Usage Graph, basé sur ces définitions

Vous trouverez ci-dessous un exemple simple d'utilisation. Pour illustrer cet usage, j’ai écrit un utilitaire simple comportant deux commandes: - add (ajoute un objet à une liste - un objet est composé d’un nom (chaîne), d’une valeur (int) et d’un drapeau booléen) - de la liste (listes tous les objets actuellement ajoutés)

Tout d'abord, j'ai écrit une classe Command pour la commande 'add':

[Usage("add", "Adds an object to the list")]
[CommandDescription("Add object", Name = "add")]
public class AddCommand : FubuCommand<CommandInput>
{
    public override bool Execute(CommandInput input)
    {
        State.Objects.Add(input); // add the new object to an in-memory collection

        return true;
    }
}

Cette commande prend une instance de CommandInput en tant que paramètre, je définis donc la suivante:

public class CommandInput
{
    [RequiredUsage("add"), Description("The name of the object to add")]
    public string ObjectName { get; set; }

    [ValidUsage("add")]
    [Description("The value of the object to add")]
    public int ObjectValue { get; set; }

    [Description("Multiply the value by -1")]
    [ValidUsage("add")]
    [FlagAlias("nv")]
    public bool NegateValueFlag { get; set; }
}

La commande suivante est 'list', qui est implémentée comme suit:

[Usage("list", "List the objects we have so far")]
[CommandDescription("List objects", Name = "list")]
public class ListCommand : FubuCommand<NullInput>
{
    public override bool Execute(NullInput input)
    {
        State.Objects.ForEach(Console.WriteLine);

        return false;
    }
}

La commande 'list' ne prend aucun paramètre, j'ai donc défini une classe NullInput pour ceci:

public class NullInput { }

Il ne reste plus qu'à câbler cela dans la méthode Main (), comme ceci:

    static void Main(string[] args)
    {
        var factory = new CommandFactory();
        factory.RegisterCommands(typeof(Program).Assembly);

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

Le programme fonctionne comme prévu, donnant des indications sur l'utilisation correcte au cas où des commandes seraient invalides:

  ------------------------
    Available commands:
  ------------------------
     add -> Add object
    list -> List objects
  ------------------------

Et un exemple d'utilisation de la commande 'add':

Usages for 'add' (Add object)
  add <objectname> [-nv]

  -------------------------------------------------
    Arguments
  -------------------------------------------------
     objectname -> The name of the object to add
    objectvalue -> The value of the object to add
  -------------------------------------------------

  -------------------------------------
    Flags
  -------------------------------------
    [-nv] -> Multiply the value by -1
  -------------------------------------
2
Cristian Lupascu

Commandlets Powershell.

Analyse effectuée par powershell en fonction des attributs spécifiés dans les commandlets, du support des validations, des jeux de paramètres, du traitement en pipeline, du signalement des erreurs, de l'aide et, mieux encore, du retour des objets .NET à utiliser dans d'autres commandlets.

Quelques liens que j'ai trouvés utiles pour commencer:

2
hannasm

Mon préféré est http://www.codeproject.com/KB/recipes/plossum_commandline.aspx par Peter Palotas:

[CommandLineManager(ApplicationName="Hello World",
    Copyright="Copyright (c) Peter Palotas")]
class Options
{
   [CommandLineOption(Description="Displays this help text")]
   public bool Help = false;

   [CommandLineOption(Description = "Specifies the input file", MinOccurs=1)]
   public string Name
   {
      get { return mName; }
      set
      {
         if (String.IsNullOrEmpty(value))
            throw new InvalidOptionValueException(
                "The name must not be empty", false);
         mName = value;
      }
   }

   private string mName;
}
2
Raphael Bossek

C # CLI est une bibliothèque d’analyses en ligne de commande très simple que j’ai écrite. C'est bien documenté et open source.

2
Bernard

Analyseur de ligne de commande Genghis est peut-être un peu dépassé, mais il est très complet et fonctionne assez bien pour moi.

1
devdimi

Je suggérerais la bibliothèque open source CSharpOptParse . Il analyse la ligne de commande et hydrate un objet .NET défini par l'utilisateur avec l'entrée de ligne de commande. J'utilise toujours cette bibliothèque pour écrire une application console C #.

0
Stuart Lange

Veuillez utiliser le port .net de l'API clache d'Apache commons. Cela fonctionne très bien.

http://sourceforge.net/projects/dotnetcli/

et l'API d'origine pour les concepts et l'introduction

http://commons.Apache.org/cli/

0
Andreas

Une classe ad hoc très simple à utiliser pour l'analyse de ligne de commande, qui supporte les arguments par défaut.

class CommandLineArgs
{
    public static CommandLineArgs I
    {
        get
        {
            return m_instance;
        }
    }

    public  string argAsString( string argName )
    {
        if (m_args.ContainsKey(argName)) {
            return m_args[argName];
        }
        else return "";
    }

    public long argAsLong(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToInt64(m_args[argName]);
        }
        else return 0;
    }

    public double argAsDouble(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToDouble(m_args[argName]);
        }
        else return 0;
    }

    public void parseArgs(string[] args, string defaultArgs )
    {
        m_args = new Dictionary<string, string>();
        parseDefaults(defaultArgs );

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private void parseDefaults(string defaultArgs )
    {
        if ( defaultArgs == "" ) return;
        string[] args = defaultArgs.Split(';');

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private Dictionary<string, string> m_args = null;
    static readonly CommandLineArgs m_instance = new CommandLineArgs();
}

class Program
{
    static void Main(string[] args)
    {
        CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12");
        Console.WriteLine("Arg myStringArg  : '{0}' ", CommandLineArgs.I.argAsString("myStringArg"));
        Console.WriteLine("Arg someLong     : '{0}' ", CommandLineArgs.I.argAsLong("someLong"));
    }
}
0
Martin Lütken