开发者

Parse command-line with sub-commands in C# [closed]

开发者 https://www.devze.com 2023-03-16 09:25 出处:网络
Closed. This question is seeking recommendations for books, tools, software libraries, and more. It does not meet Stack Overflow guidelines guidelines. It is not currently accepting answers.
Closed. This question is seeking recommendations for books, tools, software libraries, and more. It does not meet Stack Overflow guidelines guidelines. It is not currently accepting answers.

We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.

Closed 5 years ago.

Improve this question

Is there a command-line parsing library for C# with good support for "sub-commands" in the style of git, svn etc.? For example, the "git" command has several sub-commands:

git add
git status
git diff
...

There are both global options that must precede the sub-command name, and options specific to the sub-command that must follow its name. For example, these do different things:

git -p add
git add -p

Different sub-commands might each have entirely different sets of options and arguments.

I've been using NDesk.Options, but up until now I haven't needed to implement sub-commands. I think it's flexible enough to build sub-commands on top of, but it's not entirely obvious how best to do this in a concise and elegant fashion. Is it possible to do this in NDesk.Options or is there a more suit开发者_如何学Cable C# command-line parsing library?


I'm partial to my own option parsing library, which I'm blogging about currently. I do plan to cover sub-commands, but it'll be a while before I get to it (it'll be one of the last posts).

Nito.KitchenSink.OptionParsing doesn't support sub-commands directly, but you can use the library to parse only parts of the command line, and handle the sub-commands yourself. The "global" and "sub-command-specific" option sets add an interesting twist, but it can be done like this:

using System;
using System.Linq;
using Nito.KitchenSink.OptionParsing;

class Program
{
  private sealed class GlobalOptions : OptionArgumentsBase
  {
    // Use a better name than "POption". This is just an example.
    [Option('p', OptionArgument.None)]
    public bool POption { get; set; }

    // Override Validate to allow AdditionalArguments.
    public override void Validate()
    {
    }
  }

  private sealed class AddOptions : OptionArgumentsBase
  {
    [Option('p', OptionArgument.None)]
    public bool POption { get; set; }
  }

  static int Main()
  {
    try
    {
      // Parse the entire command line into a GlobalOptions object.
      var options = OptionParser.Parse<GlobalOptions>();

      // The first entry in AdditionalArguments is our sub-command.
      if (options.AdditionalArguments.Count == 0)
        throw new OptionParsingException("No sub-command specified.");
      object subcommandOptions = null;
      string subcommand = options.AdditionalArguments[0];
      switch (subcommand)
      {
        case "add":
        {
          // Parse the remaining arguments as command-specific options.
          subcommandOptions = OptionParser.Parse<AddOptions>(options.AdditionalArguments.Skip(1));
          break;
        }
        case "status": // TODO: Parse command-specific options for this, too.
          break;
        case "diff": // TODO: Parse command-specific options for this, too.
          break;
        default:
          throw new OptionParsingException("Unknown sub-command: " + subcommand);
      }


      // At this point, we have our global options, subcommand, and subcommand options.
      Console.WriteLine("Global -p option: " + options.POption);
      Console.WriteLine("Subcommand: " + subcommand);
      var addOptions = subcommandOptions as AddOptions;
      if (addOptions != null)
        Console.WriteLine("Add-specific -p option: " + addOptions.POption);

      return 0;
    }
    catch (OptionParsingException ex)
    {
      Console.Error.WriteLine(ex.Message);
      // TODO: write out usage information.
      return 2;
    }
    catch (Exception ex)
    {
      Console.Error.WriteLine(ex);
      return 1;
    }
  }
}

The sample program above produces the following output:

>CommandLineParsingTest.exe
No sub-command specified.

>CommandLineParsingTest.exe -p
No sub-command specified.

>CommandLineParsingTest.exe test
Unknown sub-command: test

>CommandLineParsingTest.exe add
Global -p option: False
Subcommand: add
Add-specific -p option: False

>CommandLineParsingTest.exe -p add
Global -p option: True
Subcommand: add
Add-specific -p option: False

>CommandLineParsingTest.exe add -p
Global -p option: False
Subcommand: add
Add-specific -p option: True

>CommandLineParsingTest.exe -p add -p
Global -p option: True
Subcommand: add
Add-specific -p option: True

>CommandLineParsingTest.exe status
Global -p option: False
Subcommand: status

>CommandLineParsingTest.exe -p status
Global -p option: True
Subcommand: status


You can try the Open Source project "Command Line" :

http://commandline.codeplex.com/

0

精彩评论

暂无评论...
验证码 换一张
取 消