Разбор командной строки с подкомандами в 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
Вы можете попробовать проект с открытым исходным кодом "Командная строка":