当前位置: 首页 > news >正文

C#/.NET 使用 CommandLineParser 来标准化地解析命令行

CommandLineParser 是一款用于解析命令行参数的 NuGet 包。你只需要关注你的业务,而命令行解析只需要极少量的配置代码。

本文将介绍如何使用 CommandLineParser 高效写出自己程序的命令行解析部分。


本文内容

      • NuGet 包和 GitHub 开源仓库
      • 最简单的命令行解析
      • 包含多个方法的命令行解析
      • Verb,Option 和 Value
        • 参考资料

NuGet 包和 GitHub 开源仓库

  • NuGet 包:CommandLineParser
  • GitHub 开源仓库:commandlineparser/commandline

最简单的命令行解析

using System;
using System.Collections.Generic;
using CommandLine;

namespace Walterlv.Demo
{
    class Program
    {
        public class Options
        {
            [Option('f', "file", Required = true, HelpText = "需要处理的文件。")]
            public IEnumerable<string> Files { get; set; }

            [Option('o', "override", Required = false, HelpText = "是否覆盖原有文件。")]
            public bool Override { get; set; }
        }

        static void Main(string[] args)
        {
            Parser.Default.ParseArguments<Options>(args).WithParsed(Run);
        }

        private static void Run(Options option)
        {
            // 使用解析后的命令行参数进行操作。
            foreach (var file in option.Files)
            {
                var verb = option.Override ? "覆盖" : "使用";
                Console.WriteLine($"walterlv 正在{verb}文件 {file}");
            }
        }
    }
}

这个简单的 Demo 程序使用 Options 类来封装命令行参数,Parser.Default.ParseArguments 解析到的参数将存入 Options 类型的实例中。而只需要加上 WithParsed 即可在一个新的方法中使用我们解析后的 Options 实例。

这时,在命令行中就可以使用命令了:

dotnet demo.dll -f C:\Users\lvyi\Desktop\Test.txt

在命令行中使用命令

由于我们标记 Files 是必要属性,所以如果此参数没有指定,将返回命令行的使用说明。此使用说明中就包含了我们在 Option 参数中编写的 HelpText

如果你的 Options 类中单次是多单词的短语,那么建议在指定名称的时候为每一个单词之间添加一个空格。这样参数就不会让多个单词连成一片难以辨认。

例如:

public class Options
{
    [Option("long-name", Required = true, HelpText = "需要处理的文件。")]
    public string LongName { get; set; }
}

那么命令是:

dotnet demo.dll --long-name xxx

如果不指定,那么就是 --longname,这显然不好看。

包含多个方法的命令行解析

如果一个命令行程序只做一件事情,那么以上代码足以应付大多数的情况。可是有时候一个命令行程序是为了做一类事情的 —— 典型的例子就是 git 程序。当你运行 git 的时候,你可以在 git 后面加一个谓词(动词),表示执行的是哪一个命令。后面的参数是每个命令都不同的,并且第一个参数是不用指定名称的。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using CommandLine;

namespace Walterlv.Demo
{
    [Verb("check", HelpText = "检查")]
    class CheckOptions
    {
        [Value(0, HelpText = "一个 .sln 文件,一个或者多个 .csproj 文件。")]
        public IEnumerable<string> InputFiles { get; set; }
    }

    [Verb("fix", HelpText = "修复")]
    class FixOptions
    {
        [Value(0, HelpText = "一个 .sln 文件,一个或者多个 .csproj 文件。")]
        public IEnumerable<string> InputFiles { get; set; }

        [Option('o', "outputFiles", Required = true, HelpText = "修复之后的文件集合。")]
        public IEnumerable<string> OutputFiles { get; set; }

        [Option(Required = false, HelpText = "是否自动决定版本号,这将使用冲突版本号中的最新版本。")]
        public bool AutoVersion { get; set; }
    }

    class Program
    {
        static int Main(string[] args)
        {
            var exitCode = Parser.Default.ParseArguments<CheckOptions, FixOptions>(args)
                .MapResult(
                    (CheckOptions o) => CheckSolutionOrProjectFiles(o),
                    (FixOptions o) => FixSolutionOrProjectFiles(o),
                    error => 1);
            return exitCode;
        }

        private static int CheckSolutionOrProjectFiles(CheckOptions options)
        {
            return 0;
        }

        private static int FixSolutionOrProjectFiles(FixOptions options)
        {
            return 0;
        }
    }
}

对于这一段程序,我们可以使用两种不同的谓词来执行命令:

dotnet demo.dll check C:\Users\lvyi\Desktop\Test\Test.csproj
dotnet demo.dll fix C:\Users\lvyi\Desktop\Test\Test.csproj -o C:\Users\lvyi\Desktop\TestFix\Test.csproj

Verb,Option 和 Value

Verb 是在一个命令行选项的 Option 类上标记的,用于指定命令的类别。每一个 Verb 标记的类别都可以有自己独立的一套命令行参数。

Option 是命名的命令行参数。在命令行中,你必须指定命令行缩写或者全称来指定命令行参数的不同类型。

Value 是命令行的无名参数,它是靠在命令行谓词后面的参数位置来确定解析到哪一个属性上的。


参考资料

  • commandlineparser/commandline: The best C# command line parser that brings standardized *nix getopt style, for .NET. Includes F# support
  • Home · commandlineparser/commandline Wiki
  • C#命令行解析工具 - 林德熙
  • The week in .NET – Command Line Parser Library, .NET South East - .NET Blog

我的博客会首发于 https://walterlv.com/,而 CSDN 和博客园仅从其中摘选发布,而且一旦发布了就不再更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://blog.csdn.net/wpwalter),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • 使用 WPF 开发一个 Windows 屏幕保护程序
  • 在 Windows 10 中开启移动 WLAN 热点
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • 在 Roslyn 分析语法树时添加条件编译符号的支持
  • 自然码的形码
  • 出于迁移项目的考虑,GitHub 中 Fork 出来的项目,如何与原项目断开 Fork 关系?
  • 只需 5 秒钟,你就能取到 WPF 程序的超高分辨率超高清截图
  • 谨慎使用 FileInfo.Exists 实例方法,而是使用 File.Exists 静态方法替代
  • UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • int? 竟然真的可以是 null!.NET/C# 确定可空值类型 NullableT 实例的真实类型
  • Slack 开发入门之 Incoming Webhooks:往 Slack 的 Channel 中发消息
  • 三值 bool? 进行与或运算后的结果
  • 为什么我们不应该使用微信或者 QQ 作为团队协作的 IM 工具?
  • 78. Subsets
  • Apache的80端口被占用以及访问时报错403
  • bearychat的java client
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • js继承的实现方法
  • js数组之filter
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • Linux各目录及每个目录的详细介绍
  • rabbitmq延迟消息示例
  • Redux 中间件分析
  • 关于Java中分层中遇到的一些问题
  • 记录:CentOS7.2配置LNMP环境记录
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 看域名解析域名安全对SEO的影响
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 深度学习在携程攻略社区的应用
  • 微信小程序开发问题汇总
  • 正则表达式小结
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • #大学#套接字
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • $(selector).each()和$.each()的区别
  • (09)Hive——CTE 公共表达式
  • (2020)Java后端开发----(面试题和笔试题)
  • (4.10~4.16)
  • (arch)linux 转换文件编码格式
  • (javascript)再说document.body.scrollTop的使用问题
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (四) Graphivz 颜色选择
  • (五)c52学习之旅-静态数码管
  • (转)编辑寄语:因为爱心,所以美丽
  • .net framework profiles /.net framework 配置
  • /etc/motd and /etc/issue
  • @ConfigurationProperties注解对数据的自动封装
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [17]JAVAEE-HTTP协议
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林
  • [BUG]vscode插件live server无法自动打开浏览器
  • [BZOJ]4817: [Sdoi2017]树点涂色