web-dev-qa-db-ja.com

C#でコマンドライン引数を解析するための最良の方法は?

パラメータを受け取るコンソールアプリケーションを構築するときは、Main(string[] args)に渡される引数を使うことができます。

過去に私は単にその配列をインデックス付け/ループし、値を抽出するためにいくつかの正規表現をしました。しかし、コマンドがより複雑になると、構文解析はかなり醜くなります。

だから私は興味がある:

  • あなたが使う図書館
  • あなたが使うパターン

コマンドは常に ここで回答された のような共通の標準に従っていると仮定します。

733
Paul Stovell

NDesk.OptionsDocumentation )または /Mono.Options (同じAPI、異なる名前空間)の使用を強くお勧めします。ドキュメントからの の例

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

私は本当にCommand Line Parser Library( http://commandline.codeplex.com/ )が好きです。それは属性を介してパラメータを設定するための非常にシンプルでエレガントな方法を持っています。

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

WPF TestApiライブラリ には、C#開発用の最も優れたコマンドラインパーサーの1つが付属しています。 Ivo Manolovの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

誰もが自分自身のペットのコマンドラインパーサを持っているように見えます。

http://bizark.codeplex.com/ /

このライブラリは コマンドラインパーサ を含み、これはコマンドラインからの値でクラスを初期化します。それはたくさんの機能を持っています(私は何年もかけてそれを作り上げてきました)。

のドキュメントから ...

BizArkフレームワークのコマンドライン解析には、次の主な機能があります。

  • 自動初期化: クラスプロパティはコマンドライン引数に基づいて自動的に設定されます。
  • デフォルトプロパティ: プロパティ名を指定せずに値を送信する。
  • 値変換: BizArkにも含まれている強力なConvertExクラスを使用して、値を適切な型に変換します。
  • ブール型フラグ: 単純に引数を使用する(ex、trueの場合は/ b、falseの場合は/ b-)、またはtrue/false、yes/noなどの値を追加することによってフラグを指定できます。
  • 引数配列: コマンドライン名の後に複数の値を追加して、配列として定義されているプロパティを設定するだけです。 Ex、/ x 1 2 3はxに配列{1、2、3}を入力します(xは整数の配列として定義されていると仮定します)。
  • コマンドラインエイリアス: プロパティでは、複数のコマンドラインエイリアスをサポートできます。たとえば、ヘルプはエイリアス?を使用します。
  • 部分的な名前の認識: あなたはフルネームや別名を綴る必要はありません。パーサーが他のものからプロパティ/別名を明確にするのに十分な綴りをしてください。
  • ClickOnceをサポートします。 ClickOnce展開アプリケーションのURLでクエリ文字列として指定されている場合でも、プロパティを初期化できます。コマンドライン初期化メソッドは、ClickOnceとして実行されているかどうかを検出するので、使用するときにコードを変更する必要はありません。
  • 自動的に/?を作成しますhelp: これはコンソールの幅を考慮に入れたNiceフォーマットを含みます。
  • コマンドライン引数をファイルにロード/保存します。 これは、複数回実行したい、大きくて複雑なコマンドライン引数のセットが複数ある場合に特に便利です。
14
Brian

しばらく前にC#コマンドライン引数パーサーを書きました。その時: http://www.codeplex.com/CommandLineArguments

13
PeterH

_ clap _ (コマンドライン引数パーサ)は使えるAPIを持っており、素晴らしく文書化されています。あなたはメソッドを作り、パラメータに注釈を付けます。 https://github.com/adrianaisemberg/CLAP

9
Colonel Panic

この問題には数多くの解決策があります。完全性のために、そして誰かが望むなら代替手段を提供するために私は私の google code library の2つの役に立つクラスのためにこの答えを加えています。

1つ目はArgumentListで、これはコマンドラインパラメータの解析のみを担当します。スイッチ '/ x:y'または '-x = y'で定義された名前と値のペアを収集し、さらに '名前のない'エントリのリストも収集します。それは基本です 使い方はここで説明しますここでクラスを見る .

この2番目の部分は CommandInterpreter です。これはあなたの.Netクラスから完全に機能的なコマンドラインアプリケーションを作成します。例として:

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

上記のコード例では、次のコードを実行できます。

Program.exe DoSomething "文字列値" 5

- または -

Program.exe dosomething/ivalue = 5 -svalue: "文字列値"

それはそれと同じくらい簡単か、あなたがそれをする必要があるのと同じくらい複雑です。 ソースコードをレビューすることができますヘルプを見る 、または バイナリをダウンロードする

5
csharptest.net

あなたは私のものが好きかもしれません Rug.Cmd

使いやすく拡張可能なコマンドライン引数パーサ。ハンドル:Bool、プラス/マイナス、文字列、文字列リスト、CSV、列挙型。

'/?'を内蔵ヘルプモード.

'/ ??'に内蔵そして '/?D'ドキュメントジェネレータモード。

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

編集:これは私のプロジェクトなので、この答えは第三者からの支持と見なされるべきではありません。それは私が書くすべてのコマンドラインベースのプログラムのために私はそれを使用すると言った、それはオープンソースであり、それは他の人がそれから恩恵を受けるかもしれない私の希望です。

4
Phill Tew

私は その方が好きです 、引数に「ルールを定義する」必要があるかどうかにかかわらず、...

もしあなたがUnixの人なら、 GNU Getopt .NET portが好きかもしれません。

4
Xn0vv3r

http://www.codeplex.com/commonlibrarynet にコマンドライン引数パーサーがあります。

それはを使用して引数を解析することができます
1。属性
2。明示的な呼び出し
3。複数の引数からなる1行OR文字列配列

それは次のようなことを扱うことができます:

- config :Qa - startdate :$ {today} - region : 'ニューヨーク'の設定01

使い方はとても簡単です。

3
jerome

これは私がNovellのOptionsクラスに基づいて書いたハンドラです。

これはwhile (input !="exit")スタイルのループを実行するコンソールアプリケーション、例えばFTPコンソールのような対話型コンソールを対象としています。

使用例

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

そして源:

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

私は最近、FubuCoreコマンドラインの構文解析の実装に遭遇しました。

  • それは使いやすいです - 私はそれのためのドキュメンテーションを見つけることができませんでしたが、FubuCoreソリューションはどんなドキュメンテーションよりも機能性について話すニースのユニットテストのセットを含むプロジェクトも提供します
  • それは私が私のコマンドライン解析アプリで持っていた素敵なオブジェクト指向のデザイン、コードの繰り返しや他のものを持っていません
  • それは宣言的です:あなたは基本的にCommandsのためのクラスとパラメータのセットを書き、様々なオプションを設定するためにそれらを属性で装飾します(例えば、名前、説明、必須/オプション)
  • これらの定義に基づいて、ライブラリはNice Usage Graphも印刷します。

以下は、これを使用する方法に関する簡単な例です。使い方を説明するために、2つのコマンドを持つ簡単なユーティリティを書きました。現在追加されているすべてのオブジェクト)

まず最初に、 'add'コマンド用のCommandクラスを書きました。

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

このコマンドはCommandInputインスタンスをパラメータとして受け取るので、次に定義します。

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

次のコマンドは 'list'です。これは次のように実装されています。

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

'list'コマンドはパラメータを取らないので、このためにNullInputクラスを定義しました。

public class NullInput { }

あとは、これをMain()メソッドに結び付けるだけです。

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

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

プログラムは期待どおりに動作し、コマンドが無効な場合の正しい使用法についてのヒントを表示します。

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

'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コマンドレット。

コマンドレットで指定された属性、検証のサポート、パラメータセット、パイプライン処理、エラー報告、ヘルプ、および他のコマンドレットで使用するための.NETオブジェクトの戻り値に基づいて、powershellによって解析が行われます。

いくつかのリンクは私が始めて参考になった:

2
hannasm

私の個人的なお気に入りは http://www.codeproject.com/KB/recipes/plossum_commandline.aspx 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 は、私が書いた非常に単純なコマンドライン引数解析ライブラリです。それはよく文書化されたオープンソースです。

2
Bernard

Genghis Command Line Parser はちょっと時代遅れかもしれませんが、非常に機能が充実していて私にとってはかなりうまくいきます。

1
devdimi

オープンソースのライブラリ CSharpOptParse をお勧めします。コマンドラインを解析し、コマンドライン入力でユーザー定義の.NETオブジェクトをハイドレートします。 C#コンソールアプリケーションを書くとき、私はいつもこのライブラリに目を向けます。

0
Stuart Lange

Apache commons cli APIの.netポートを使用してください。これはとてもうまくいきます。

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

そして概念と導入のためのオリジナルのAPI

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

0
Andreas

デフォルトの引数をサポートする、コマンドライン解析のための非常に簡単で使いやすいアドホッククラス。

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