Skip to main content

commandline-cheatsheet

Use when building command-line applications in .NET with System.CommandLine. Covers command/option/argument definitions, middleware, tab completion, parsing, and hosting integration for CLI tools. USE FOR: building CLI applications with typed argument parsing, creating dotnet tools with subcommands, System.CommandLine setup and configuration, adding tab completion to CLI apps, parsing and validating command-line arguments DO NOT USE FOR: executing external CLI processes (use cliwrap), rendering rich terminal UI with tables and progress bars (use spectre-console), building web APIs (use ASP.NET Core), simple Console.ReadLine input

소스 정보

저장소
Tyler-R-Kendrick/agent-skills
최근 소스 활동
2026년 2월 11일 05:14
감지된 SKILL.md 언어
영어
스타
11
포크
4

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
21 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
commandline-cheatsheet
description
Use when building command-line applications in .NET with System.CommandLine. Covers command/option/argument definitions, middleware, tab completion, parsing, and hosting integration for CLI tools. USE FOR: building CLI applications with typed argument parsing, creating dotnet tools with subcommands, System.CommandLine setup and configuration, adding tab completion to CLI apps, parsing and validating command-line arguments DO NOT USE FOR: executing external CLI processes (use cliwrap), rendering rich terminal UI with tables and progress bars (use spectre-console), building web APIs (use ASP.NET Core), simple Console.ReadLine input
license
MIT
metadata
{"displayName":"Command-Line Cheatsheet","author":"Tyler-R-Kendrick","version":"1.0.0"}
compatibility
claude, copilot, cursor
references
[{"title":"System.CommandLine Documentation","url":"https://learn.microsoft.com/dotnet/standard/commandline"},{"title":"System.CommandLine GitHub Repository","url":"https://github.com/dotnet/command-line-api"},{"title":"System.CommandLine NuGet Package","url":"https://www.nuget.org/packages/System.CommandLine"}]
# Command-Line Cheatsheet ## Overview System.CommandLine is the official .NET library for building command-line applications with typed argument parsing, automatic help generation, tab completion, and middleware support. It provides a structured way to define commands, options, and arguments that map directly to handler methods, with built-in validation and error reporting. ## NuGet Packages ```bash dotnet add package System.CommandLine dotnet add package System.CommandLine.Hosting # Generic Host integration ``` ## Minimal CLI Application ```csharp using System.CommandLine; var nameOption = new Option<string>( name: "--name", description: "Your name") { IsRequired = true }; var greetingOption = new Option<string>( name: "--greeting", description: "The greeting to use", getDefaultValue: () => "Hello"); var rootCommand = new RootCommand("A simple greeting CLI tool"); rootCommand.AddOption(nameOption); rootCommand.AddOption(greetingOption); rootCommand.SetHandler((string name, string greeting) => { Console.WriteLine($"{greeting}, {name}!"); }, nameOption, greetingOption); return await rootCommand.InvokeAsync(args); // Usage: myapp --name Alice --greeting "Good morning" ``` ## Commands with Subcommands ```csharp using System.CommandLine; var rootCommand = new RootCommand("Project management CLI"); // 'new' command var newCommand = new Command("new", "Create a new project"); var templateArg = new Argument<string>("template", "Project template name"); var outputOption = new Option<DirectoryInfo>( "--output", "Output directory") { IsRequired = false }; newCommand.AddArgument(templateArg); newCommand.AddOption(outputOption); newCommand.SetHandler((string template, DirectoryInfo? output) => { var dir = output?.FullName ?? Directory.GetCurrentDirectory(); Console.WriteLine($"Creating '{template}' project in {dir}"); }, templateArg, outputOption); // 'build' command var buildCommand = new Command("build", "Build the project"); var configOption = new Option<string>( "--configuration", () => "Debug", "Build configuration"); configOption.AddAlias("-c"); var verbosityOption = new Option<Verbosity>( "--verbosity", () => Verbosity.Normal, "Output verbosity"); verbosityOption.AddAlias("-v"); buildCommand.AddOption(configOption); buildCommand.AddOption(verbosityOption); buildCommand.SetHandler((string config, Verbosity verbosity) => { Console.WriteLine($"Building with configuration={config}, verbosity={verbosity}"); }, configOption, verbosityOption); // 'test' command with nested subcommands var testCommand = new Command("test", "Run tests"); var unitCommand = new Command("unit", "Run unit tests"); var integrationCommand = new Command("integration", "Run integration tests"); var filterOption = new Option<string?>("--filter", "Test filter expression"); unitCommand.AddOption(filterOption); unitCommand.SetHandler((string? filter) => { Console.WriteLine($"Running unit tests{(filter != null ? $" with filter: {filter}" : "")}"); }, filterOption); integrationCommand.SetHandler(() => { Console.WriteLine("Running integration tests"); }); testCommand.AddCommand(unitCommand); testCommand.AddCommand(integrationCommand); rootCommand.AddCommand(newCommand); rootCommand.AddCommand(buildCommand); rootCommand.AddCommand(testCommand); return await rootCommand.InvokeAsync(args); enum Verbosity { Quiet, Normal, Detailed, Diagnostic } // Usage: // myapp new webapp --output ./MyApp // myapp build -c Release -v Detailed // myapp test unit --filter "Category=Smoke" // myapp test integration ``` ## Options, Arguments, and Aliases | Concept | Description | Example | |---------|-------------|---------| | `Option<T>` | Named parameter with `--` prefix | `--output`, `-o` | | `Argument<T>` | Positional parameter (no prefix) | `myapp <file>` | | `AddAlias` | Short alias for an option | `-c` for `--configuration` | | `IsRequired` | Makes an option mandatory | `{ IsRequired = true }` | | `getDefaultValue` | Factory for default values | `() => "Debug"` | | `FromAmong` | Restricts to allowed values | `FromAmong("Debug", "Release")` | ## Argument Validation ```csharp using System.CommandLine; var portOption = new Option<int>("--port", "Server port"); portOption.AddValidator(result => { var port = result.GetValueForOption(portOption); if (port < 1024 || port > 65535) { result.ErrorMessage = "Port must be between 1024 and 65535"; } }); var fileArgument = new Argument<FileInfo>("file", "Input file"); fileArgument.AddValidator(result => { var file = result.GetValueForArgument(fileArgument); if (file is not null && !file.Exists) { result.ErrorMessage = $"File not found: {file.FullName}"; } }); // Restrict to specific values var envOption = new Option<string>("--environment"); envOption.FromAmong("Development", "Staging", "Production"); ``` ## Global Options ```csharp var verboseOption = new Option<bool>("--verbose", "Enable verbose logging"); verboseOption.AddAlias("-V"); var rootCommand = new RootCommand("My CLI"); rootCommand.AddGlobalOption(verboseOption); // Available to all subcommands var serveCommand = new Command("serve", "Start the server"); serveCommand.SetHandler((bool verbose) => { if (verbose) Console.WriteLine("Verbose mode enabled"); Console.WriteLine("Starting server..."); }, verboseOption); rootCommand.AddCommand(serveCommand); // Usage: myapp serve --verbose // Usage: myapp --verbose serve (global options work before or after subcommand) ``` ## Hosting Integration Integrate System.CommandLine with the .NET Generic Host for DI, configuration, and logging. ```csharp using System.CommandLine; using System.CommandLine.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; var rootCommand = new RootCommand("CLI with hosting"); var nameOption = new Option<string>("--name", "User name") { IsRequired = true }; rootCommand.AddOption(nameOption); rootCommand.SetHandler(async (IHost host) => { var greeter = host.Services.GetRequiredService<GreeterService>(); var parseResult = host.Services.GetRequiredService<ParseResult>(); var name = parseResult.GetValueForOption(nameOption)!; await greeter.GreetAsync(name); }); var builder = new CommandLineBuilder(rootCommand) .UseHost(hostBuilder => { hostBuilder.ConfigureServices(services => { services.AddTransient<GreeterService>(); }); hostBuilder.ConfigureLogging(logging => { logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Information); }); }) .UseDefaults(); return await builder.Build().InvokeAsync(args); public class GreeterService(ILogger<GreeterService> logger) { public Task GreetAsync(string name) { logger.LogInformation("Greeting user: {Name}", name); Console.WriteLine($"Hello, {name}!"); return Task.CompletedTask; } } ``` ## Middleware ```csharp var builder = new CommandLineBuilder(rootCommand) .UseDefaults() .AddMiddleware(async (context, next) => { var sw = System.Diagnostics.Stopwatch.StartNew(); Console.WriteLine($"Executing: {context.ParseResult.CommandResult.Command.Name}"); await next(context); sw.Stop(); Console.WriteLine($"Completed in {sw.ElapsedMilliseconds}ms"); }); var parser = builder.Build(); return await parser.InvokeAsync(args); ``` ## File and Directory Arguments ```csharp var inputFile = new Argument<FileInfo>("input", "Input file path"); var outputDir = new Option<DirectoryInfo>( "--output-dir", () => new DirectoryInfo("."), "Output directory"); var convertCommand = new Command("convert", "Convert a file"); convertCommand.AddArgument(inputFile); convertCommand.AddOption(outputDir); convertCommand.SetHandler((FileInfo input, DirectoryInfo outDir) => { if (!input.Exists) { Console.Error.WriteLine($"File not found: {input.FullName}"); return; } Console.WriteLine($"Converting {input.Name} to {outDir.FullName}"); }, inputFile, outputDir); ``` ## Creating a dotnet Tool ```xml <!-- .csproj file --> <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <PackAsTool>true</PackAsTool> <ToolCommandName>mytool</ToolCommandName> <PackageId>MyOrg.MyTool</PackageId> <Version>1.0.0</Version> </PropertyGroup> <ItemGroup> <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.*" /> </ItemGroup> </Project> ``` ```bash # Pack and install locally dotnet pack dotnet tool install --global --add-source ./nupkg MyOrg.MyTool # Usage mytool build -c Release mytool test unit --filter "Priority=1" ``` ## Best Practices - Use `RootCommand` with descriptive text as the entry point and organize functionality into `Command` subcommands rather than overloading the root with many options. - Add both long (`--configuration`) and short (`-c`) aliases for frequently used options to reduce typing in interactive use while keeping discoverability for scripts. - Use `Option<T>` with strongly-typed generics (`Option<int>`, `Option<FileInfo>`, `Option<Verbosity>`) instead of `Option<string>` with manual parsing to get automatic validation and help text. - Set `IsRequired = true` on mandatory options and provide `getDefaultValue` factories on optional ones so the help text accurately reflects what is required vs. optional. - Use `AddValidator` for custom validation rules (port ranges, file existence, format checks) to provide clear error messages before the handler runs. - Use `FromAmong` to restrict string options to a fixed set of allowed values (e.g., environments, log levels) with automatic validation and tab completion. - Integrate with `System.CommandLine.Hosting` for applications that need dependency injection, `IConfiguration`, or `ILogger` rather than constructing services manually in handlers. - Add `AddGlobalOption` for cross-cutting options like `--verbose`, `--output-format`, or `--no-color` that apply to all subcommands without repeating them. - Set `<PackAsTool>true</PackAsTool>` in the .csproj to distribute the CLI as a `dotnet tool` that users install with `dotnet tool install`. - Use `CommandLineBuilder.UseDefaults()` to enable automatic help (`--help`), version (`--version`), parse error reporting, and suggest-typo features without manual configuration.
GitHub에서 보기