命令行参数
平常在日常的开发过程中,会经常用到命令行工具。如cmd下的各种命令。
以下为sc命令执行后的截图,可以看到,由于没有输入任何附带参数,所以程序并未执行任何操作,只是输出了描述和用法。
系统在创建一个新进程时,会传一个命令行给它,也就是命令行字符串。
程序需要对命令行字符串进行解析,并执行相应操作。
如使用sc query可以查询当前系统的服务:
在C#中的控制台程序中,Main函数中传入的args字符串数组,就是系统传入进程的命令行参数。
在构建具有复杂命令行参数的控制台程序时 ,手动解析参数就变得非常麻烦。这里推荐一个开源的库,可以更加方便的解析命令行参数。
System.CommandLine介绍
System.CommandLine是一个基于.Net Standard 2.0(支持.Net FrameWork 4.6.1.2+和.Net Core 2.0+)的命令行参数解析库,项目地址 https://github.com/dotnet/command-line-api,目前,该项目还是属于beta状态,期待以后的正式版本。
由于不是正式版本,在Nuget中引用时,需要钩上Include prerelease,才能找到这个包。
System.CommandLine的一些基本概念
Token(标记)
命令行的每个单词都是一个标记,如下面的"sc"、"query"和"eventlog"都是一个Token
Commands(命令)
Commands就是应用程序根据Token执行相应的操作(在System.CommandLine库中,对应 Command类)
Root Command(根命令)
根命令是代表可执行程序本身的Commands,如 sc(在System.CommandLine库中,对应RootCommand类)
SubCommands(子命令)
一些命令行程序会有SubCommands,如上面的sc query中的query就是子命令(在System.CommandLine,对应Command类)
Options(可选项)
Options就是传递给Commands的命名参数,如 app -myoption123中的 -myoption 123就是一个Options
Argument(参数)
参数就是传递给选项或命令的值。
说明:
常规的调用如下:
xx.exe [options] <argument> [command]
Delimiters(分隔符)
分隔符就是把Options的命令和值分开的符号
如下三种写法都是一样的,可以使用空格、=或 :符号
app -myoption 123
app -myoption=123
app -myoption:123
Aliases(别名)
可以为命令或选项设置较短的别名,如
-v, --verbose
--o, --option
System.CommandLine使用
在下面的示例中,我们会构建一个简单的控制台爬虫工具。
1、使用Visual Studio 2019创建一个.Net Core控制台程序crawler-line
2、导入System.CommandLine包
3、创建一个RootCommand
1 var rootCommand = new RootCommand 2 { 3 new Argument<string>( 4 "url","web site url"), 5 new Option<bool>(new string[]{ "--gethtml" ,"-html"},"Get html source"), 6 new Option<bool>(new string[]{ "--getimage" ,"-image"},"Get images"), 7 new Option<bool>(new string[]{ "--regex-option" ,"-regex"},"Use regex"), 8 new Option<bool>(new string[]{ "--htmlagilitypack-option", "-agpack"},"Use HtmlAgilityPack"), 9 new Option<bool>(new string[]{ "--anglesharp-option", "-agsharp"},"Use AngleSharp"), 10 new Option<string>(new string[]{ "--download-path" ,"-path"},"Designate download path"),13 };
说明:
可通过Option类的构造函数重载,为Option指定默认值。
1 public Option(string alias, Func<T> getDefaultValue, string? description = null);
如上面的-path Option,指定默认值为D:\download,如下:
1 new Option<string>(new string[]{ "--download-path" ,"-path"},getDefaultValue:()=>"D:\\download","Designate download path"),
也可以先实例化RootCommand对象,再通过Add的方式添加Argument和Option,如下:
1 var rootCommand = new RootCommand(); 2 //添加 Argument 3 rootCommand.AddArgument(new Argument<string>("url","web site url")); 4 //添加 Option 5 rootCommand.AddOption(new Option<string>(new string[] {"--download-path","-path" },"download path"));
4、添加当前命令行程序的描述信息
1 rootCommand.Description = ".Net Core command-line crawler.";
5、解析Argument和Option
rootCommand.Handler = CommandHandler.Create<string, bool, bool, bool, bool, bool, string>((string url, bool html, bool image, bool regex, bool agpack, bool agsharp, string path) => { });
如果觉得参数太长,可以封装成类,再进行调用,如下:
1 public class CrawlerOption 2 { 3 public string Url { get; set; } 4 public bool GetHtml { get; set; } 5 public bool GetImage { get; set; } 6 public bool RegexOption { get; set; } 7 public bool HtmlagilitypackOption { get; set; } 8 public bool AnglesharpOption { get; set; } 9 public string DownloadPath { get; set; } 10 }
1 rootCommand.Handler = CommandHandler.Create<CrawlerOption>((crawlerOption) => 2 { 3 4 })
6、添加Command并为Command添加处理函数
1 //添加 Command 2 var githubCommand = new Command("github", "fork me on github"); 3 //添加 Command的处理函数 4 githubCommand.Handler = CommandHandler.Create(() => { System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("cmd", $"/c start https://github.com/zhaotianff/Crawler-Line")); });5 //将Command添加 到RootCommand 6 rootCommand.AddCommand(githubCommand);
说明:
1、RootCommand是顶级命令,RootCommand可以添加Command,Command又可以再添加SubCommand。如此可以无限循环,没有限制 。但建议还是不要添加太多级的Command,调用的时候会不太友好
2、Command和RootCommand原理一样,如果需要为Command添加Argument、Option和Command,可以参照前面的示例
7、调用解析
1 return rootCommand.InvokeAsync(args).Result;
8、调用示例
#执行github command crawler-line.exe github #执行github subcommand crawler-line.exe github sub #执行argument option crawler-line.exe http://www.baidu.com -path "D:\test"
特别提示:
前面示例中,都是为RootCommand添加的Argument和Option,如果又指定 -path(Option),又执行github(Command)肯定会失败。因为github这个命令是RootCommand的子命令,而-path选项是为RootCommand添加的
示例代码
C#命令行参数解析库System.CommandLine介绍