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 questionIs 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/
精彩评论