Разбор командной строки с подкомандами в C#

Существует ли библиотека синтаксического анализа командной строки для C# с хорошей поддержкой "подкоманд" в стиле git, svn и т. Д.? Например, команда "git" имеет несколько подкоманд:

git add
git status
git diff
...

Существуют как глобальные параметры, которые должны предшествовать имени подкоманды, так и параметры, относящиеся к подкоманде, которая должна следовать за ее именем. Например, они делают разные вещи:

git -p add
git add -p

Различные подкоманды могут иметь разные наборы параметров и аргументов.

Я использовал NDesk.Options, но до сих пор мне не нужно было реализовывать подкоманды. Я думаю, что он достаточно гибкий, чтобы создавать подкоманды поверх него, но не совсем очевидно, как лучше всего сделать это кратко и элегантно. Возможно ли это сделать в NDesk.Options или есть более подходящая библиотека синтаксического анализа командной строки C#?

2 ответа

Я неравнодушен к своей собственной библиотеке разбора опций, о которой я сейчас пишу. Я планирую охватить подкоманды, но пройдет некоторое время, прежде чем я доберусь до них (это будет одно из последних сообщений).

Nito.KitchenSink.OptionParsing не поддерживает подкоманды напрямую, но вы можете использовать библиотеку для анализа только частей командной строки и обработки подкоманд самостоятельно. Наборы опций "global" и "sub-command-specific" добавляют интересный поворот, но это можно сделать так:

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

Приведенный выше пример программы производит следующий вывод:

>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

Вы можете попробовать проект с открытым исходным кодом "Командная строка":

http://commandline.codeplex.com/

Другие вопросы по тегам