it-swarm.com.de

Beste Möglichkeit zum Parsen von Befehlszeilenargumenten in C #?

Beim Erstellen von Konsolenanwendungen, die Parameter verwenden, können Sie die an Main(string[] args) übergebenen Argumente verwenden.

In der Vergangenheit habe ich dieses Array einfach indexiert/geloopt und ein paar reguläre Ausdrücke erstellt, um die Werte zu extrahieren. Wenn die Befehle jedoch komplizierter werden, kann das Parsen ziemlich hässlich werden.

Ich interessiere mich also für:

  • Bibliotheken, die Sie verwenden
  • Von Ihnen verwendete Muster

Angenommen, die Befehle halten sich immer an gängige Standards wie hier beantwortet .

733
Paul Stovell

Ich würde dringend empfehlen, NDesk.Options ( Documentation ) und/oder Mono.Options (gleiche API, unterschiedlicher Namespace) zu verwenden. Ein Beispiel aus der Dokumentation :

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

Ich mag die Command Line Parser Library ( http://commandline.codeplex.com/ ). Es hat eine sehr einfache und elegante Art, Parameter über Attribute einzurichten:

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

Die WPF-TestApi-Bibliothek enthält einen der schönsten Befehlszeilenparser für die C # -Entwicklung. Ich empfehle dringend, sich das anzuschauen, von Ivo Manolovs Blog auf der 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

Es sieht so aus, als ob jeder seine eigenen Kommandozeilen-Parser hat, ich sollte auch meine hinzufügen :).

http://bizark.codeplex.com/

Diese Bibliothek enthält einen Kommandozeilen-Parser , der eine Klasse mit den Werten aus der Kommandozeile initialisiert. Es hat eine Menge Funktionen (ich habe es über viele Jahre aufgebaut).

Aus der Dokumentation ...

Die Befehlszeilenanalyse im BizArk-Framework weist die folgenden Hauptfunktionen auf:

  • Automatische Initialisierung: Klasseneigenschaften werden basierend auf den Befehlszeilenargumenten automatisch festgelegt.
  • Standardeigenschaften: Senden Sie einen Wert ohne Angabe des Eigenschaftsnamens.
  • Wertkonvertierung: Verwendet die leistungsstarke ConvertEx-Klasse, die auch in BizArk enthalten ist, um Werte in den richtigen Typ zu konvertieren.
  • Boolesche Flags: Flags können einfach durch Verwendung des Arguments (ex,/b für true und/b- für false) oder durch Hinzufügen des Werts true angegeben werden/falsch, ja/nein usw.
  • Argument-Arrays: Fügen Sie einfach mehrere Werte nach dem Befehlszeilennamen hinzu, um eine als Array definierte Eigenschaft festzulegen. Beispiel:/x 1 2 3 füllt x mit dem Array {1, 2, 3} (vorausgesetzt, x ist als Array von Ganzzahlen definiert).
  • Befehlszeilen-Aliase: Eine Eigenschaft kann mehrere Befehlszeilen-Aliase für sie unterstützen. In der Hilfe wird beispielsweise der Alias? Verwendet.
  • Teilweise Namenserkennung: Sie müssen weder den vollständigen Namen noch den Alias ​​buchstabieren, nur so viel, dass der Parser die Eigenschaft/den Alias ​​von der trennen kann Andere.
  • Unterstützt ClickOnce: Kann Eigenschaften auch dann initialisieren, wenn sie als Abfragezeichenfolge in einer URL für von ClickOnce bereitgestellte Anwendungen angegeben sind. Die Befehlszeileninitialisierungsmethode erkennt, ob sie als ClickOnce ausgeführt wird oder nicht, sodass sich der Code bei der Verwendung nicht ändern muss.
  • Erstellt automatisch /? help: Dies beinhaltet eine nette Formatierung, die die Breite der Konsole berücksichtigt.
  • Laden/Speichern von Befehlszeilenargumenten in eine Datei: Dies ist besonders nützlich, wenn Sie mehrere große, komplexe Sätze von Befehlszeilenargumenten haben, die Sie möchten mehrmals ausführen.
14
Brian

Ich habe vor einiger Zeit einen C # -Befehlszeilen-Parser geschrieben. Sein an: http://www.codeplex.com/CommandLineArguments

13
PeterH

CLAP (Kommandozeilenargument-Parser) hat eine verwendbare API und ist wunderbar dokumentiert. Sie erstellen eine Methode, in der Sie die Parameter mit Anmerkungen versehen. https://github.com/adrianaisemberg/CLAP

9
Colonel Panic

Es gibt zahlreiche Lösungen für dieses Problem. Der Vollständigkeit halber und um auf Wunsch eine Alternative anzubieten, füge ich diese Antwort für zwei nützliche Klassen in meine Google Code Library ein.

Das erste ist ArgumentList, das nur für das Parsen von Befehlszeilenparametern zuständig ist. Es sammelt Name-Wert-Paare, die durch die Schalter '/ x: y' oder '-x = y' definiert sind, und sammelt auch eine Liste von 'unbenannten' Einträgen. Es ist grundlegend die Verwendung wird hier besprochen , die Klasse hier ansehen .

Der zweite Teil davon ist der CommandInterpreter , der aus Ihrer .Net-Klasse eine voll funktionsfähige Befehlszeilenanwendung erstellt. Als Beispiel:

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)
        { ... }

Mit dem obigen Beispielcode können Sie Folgendes ausführen:

Program.exe DoSomething "Zeichenfolgenwert" 5

-- oder --

Program.exe dosomething/ivalue = 5 -svalue: "string value"

So einfach oder so komplex, wie Sie es brauchen. Sie können den Quellcode überprüfen , die Hilfe anzeigen oder die Binärdatei herunterladen .

5
csharptest.net

Sie können mein mögen Rug.Cmd

Einfach zu verwendender und erweiterbarer Parser für Befehlszeilenargumente. Handles: Bool, Plus/Minus, String, String-Liste, CSV, Aufzählung.

Eingebaut in '/?' Hilfemodus.

Baujahr '/ ??' und '/? D' Dokumentgenerator-Modi.

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);
        }
    }
}

Bearbeiten: Dies ist mein Projekt und als solche sollte diese Antwort nicht als Befürwortung von Dritten gesehen werden. Das heißt, ich verwende es für jedes Kommandozeilenprogramm, das ich schreibe. Es ist Open Source und ich hoffe, dass andere davon profitieren können.

4
Phill Tew

Ich mag dieses , weil Sie "Regeln definieren" können für die Argumente, die benötigt werden oder nicht, ...

oder wenn Sie ein Unix-Typ sind, dann könnte Ihnen der GNU Getopt .NET -Port gefallen.

4
Xn0vv3r

Es gibt einen Parser für Befehlszeilenargumente unter http://www.codeplex.com/commonlibrarynet

Es kann Argumente mit analysieren
1. Attribute
2. explizite Anrufe
3. einzelne Zeile mit mehreren Argumenten OR Zeichenfolgenarray

Es kann mit Dingen wie den folgenden umgehen:

- config : Qa - startdate : $ { Heute } - Region : 'New York' Einstellungen01

Es ist sehr einfach zu bedienen.

3
jerome

Dies ist ein Handler, den ich basierend auf der Klasse Novell Options geschrieben habe.

Diese richtet sich an Konsolenanwendungen, die eine while (input !="exit") -Stilschleife ausführen, z. B. eine interaktive Konsole wie eine FTP-Konsole.

Anwendungsbeispiel:

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();
    }
}

Und die Quelle:

/// <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

Ich bin kürzlich auf die FubuCore-Kommandozeilen-Parsing-Implementierung gestoßen. Die Gründe dafür sind:

  • es ist einfach zu bedienen - obwohl ich keine Dokumentation dafür gefunden habe, bietet die FubuCore-Lösung auch ein Projekt mit einer Reihe von Unit-Tests, die mehr über die Funktionalität aussagen als jede andere Dokumentation
  • es hat ein nettes objektorientiertes Design, keine Code-Wiederholung oder andere solche Dinge, die ich in meinen Kommandozeilen-Parsing-Apps hatte
  • es ist deklarativ: Sie schreiben im Grunde Klassen für die Befehle und Parametersätze und dekorieren sie mit Attributen, um verschiedene Optionen festzulegen (z. B. Name, Beschreibung, obligatorisch/optional).
  • die Bibliothek druckt sogar ein Nizza-Nutzungsdiagramm, das auf diesen Definitionen basiert

Nachfolgend finden Sie ein einfaches Beispiel zur Verwendung. Um die Verwendung zu veranschaulichen, habe ich ein einfaches Hilfsprogramm geschrieben, das zwei Befehle enthält: - add (fügt ein Objekt zu einer Liste hinzu - ein Objekt besteht aus einem Namen (String), einem Wert (int) und einem Booleschen Flag) - list (lists alle aktuell hinzugefügten Objekte)

Zunächst habe ich eine Command-Klasse für den Befehl 'add' geschrieben:

[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;
    }
}

Dieser Befehl verwendet eine CommandInput-Instanz als Parameter, daher definiere ich Folgendes:

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; }
}

Der nächste Befehl ist 'list', der wie folgt implementiert wird:

[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;
    }
}

Der Befehl 'list' akzeptiert keine Parameter, daher habe ich eine NullInput-Klasse definiert:

public class NullInput { }

Jetzt müssen Sie dies nur noch in der Main () -Methode verkabeln:

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

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

Das Programm funktioniert wie erwartet und gibt Hinweise zur korrekten Verwendung aus, falls Befehle ungültig sind:

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

Und ein Anwendungsbeispiel für den Befehl '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

Powershell Commandlets.

Analyse durch Powershell basierend auf den in den Commandlets angegebenen Attributen, Unterstützung für Validierungen, Parametersätze, Pipelining, Fehlerberichterstattung, Hilfe und am besten Rückgabe von .NET-Objekten zur Verwendung in anderen Commandlets.

Ein paar Links, die ich hilfreich fand, als ich anfing:

2
hannasm

Mein persönlicher Favorit ist http://www.codeproject.com/KB/recipes/plossum_commandline.aspx von 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 ist eine sehr einfache Parsing-Bibliothek für Befehlszeilenargumente, die ich geschrieben habe. Es ist gut dokumentiert und Open Source.

2
Bernard

Dschingis Kommandozeilen-Parser ist zwar etwas veraltet, aber das Feature ist sehr vollständig und funktioniert für mich ziemlich gut.

1
devdimi

Ich würde die Open-Source-Bibliothek vorschlagen CSharpOptParse . Es analysiert die Befehlszeile und hydratisiert ein benutzerdefiniertes .NET-Objekt mit der Befehlszeileneingabe. Ich greife beim Schreiben einer C # -Konsolenanwendung immer auf diese Bibliothek zurück.

0
Stuart Lange

Bitte benutzen Sie den .net Port der Apache Commons Cli API. Das funktioniert super.

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

und die ursprüngliche API für Konzepte und Einführung

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

0
Andreas

Eine sehr einfache, benutzerfreundliche Ad-hoc-Klasse zum Parsen der Befehlszeile, die Standardargumente unterstützt.

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