Edit

Share via


Syntax overview: Commands, options, and arguments

Important

System.CommandLine is currently in PREVIEW, and this documentation is for version 2.0 beta 5. Some information relates to prerelease product that may be substantially modified before it's released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

This article explains the command-line syntax that System.CommandLine recognizes. The information is useful to both users and developers of .NET command-line apps, including the .NET CLI.

Tokens

System.CommandLine parses command-line input into tokens, which are strings delimited by spaces. For example, consider the following command line:

dotnet tool install dotnet-suggest --global --verbosity quiet

This input is parsed by the dotnet application into tokens tool, install, dotnet-suggest, --global, --verbosity, and quiet.

Tokens are interpreted as commands, options, or arguments. The command-line app that is being invoked determines how the tokens after the first one are interpreted. The following table shows how System.CommandLine interprets the preceding example:

Token Parsed as
tool Subcommand
install Subcommand
dotnet-suggest Argument for install command
--global Option for install command
--verbosity Option for install command
quiet Argument for --verbosity option

A token can contain spaces if it's enclosed in quotation marks ("). Here's an example:

dotnet tool search "ef migrations add"

Commands

A command in command-line input is a token that specifies an action or defines a group of related actions. For example:

  • In dotnet run, run is a command that specifies an action.
  • In dotnet tool install, install is a command that specifies an action, and tool is a command that specifies a group of related commands. There are other tool-related commands, such as tool uninstall, tool list, and tool update.

Root command

The root command is the one that specifies the name of the app's executable. For example, the dotnet command specifies the dotnet.exe executable.

System.CommandLine.Command is the general-purpose class for any command or subcommand, while System.CommandLine.RootCommand is a specialized version intended for the application's root entry point, inheriting all features of System.CommandLine.Command but adding root-specific behavior and defaults, such as Help option, Version option and Suggest directive.

Subcommands

Most command-line apps support subcommands, also known as verbs. For example, the dotnet command has a run subcommand that you invoke by entering dotnet run.

Subcommands can have their own subcommands. In dotnet tool install, install is a subcommand of tool.

You can add subcommands as shown in the following example:

RootCommand rootCommand = new();

Command sub1Command = new("sub1", "First-level subcommand");
rootCommand.Subcommands.Add(sub1Command);

Command sub1aCommand = new("sub1a", "Second level subcommand");
sub1Command.Subcommands.Add(sub1aCommand);

The innermost subcommand in this example can be invoked like this:

myapp sub1 sub1a

Options

An option is a named parameter that can be passed to a command. POSIX CLIs typically prefix the option name with two hyphens (--). The following example shows two options:

dotnet tool update dotnet-suggest --verbosity quiet --global
                                  ^---------^       ^------^

As this example illustrates, the value of the option may be explicit (quiet for --verbosity) or implicit (nothing follows --global). Options that have no value specified are typically Boolean parameters that default to true if the option is specified on the command line.

For some Windows command-line apps, you identify an option by using a leading slash (/) with the option name. For example:

msbuild /version
        ^------^

System.CommandLine supports both POSIX and Windows prefix conventions.

When you configure an option, you specify the option name including the prefix:

Option<int> delayOption = new("--delay", "-d")
{
    Description = "An option whose argument is parsed as an int.",
    DefaultValueFactory = parseResult => 42,
};
Option<string> messageOption = new("--message", "-m")
{
    Description = "An option whose argument is parsed as a string."
};

RootCommand rootCommand = new();
rootCommand.Options.Add(delayOption);
rootCommand.Options.Add(messageOption);

To add an option to a command and recursively to all of its subcommands, use the System.CommandLine.Symbol.Recursive property.

Required Options

Some options have required arguments. For example in the .NET CLI, --output requires a folder name argument. If the argument is not provided, the command fails. To make an option required, set its System.CommandLine.Symbol.Required property to true, as shown in the following example:

Option<FileInfo> fileOption = new("--output")
{
    Required = true
};

If a required option has a default value (specified via DefaultValueFactory property), the option doesn't have to be specified on the command line. In that case, the default value provides the required option value.

Arguments

An argument is an unnamed parameter that can be passed to a command. The following example shows an argument for the build command.

dotnet build myapp.csproj
             ^----------^

When you configure an argument, you specify the argument name (it's not used for parsing, but it can be used for getting parsed values by name or displaying help) and type:

Argument<int> delayArgument = new("delay")
{
    Description = "An argument that is parsed as an int.",
    DefaultValueFactory = parseResult => 42
};
Argument<string> messageArgument = new("message")
{
    Description = "An argument that is parsed as a string."
};

RootCommand rootCommand = new();
rootCommand.Arguments.Add(delayArgument);
rootCommand.Arguments.Add(messageArgument);

Default Values

Both arguments and options can have default values that apply if no argument is explicitly provided. For example, many options are implicitly Boolean parameters with a default of true when the option name is in the command line. The following command-line examples are equivalent:

dotnet tool update dotnet-suggest --global
                                  ^------^

dotnet tool update dotnet-suggest --global true
                                  ^-----------^

An argument that is defined without a default value is treated as a required argument.

Parse errors

Options and arguments have expected types, and an error is produced when the value can't be parsed. For example, the following command errors because "silent" isn't one of the valid values for --verbosity:

dotnet build --verbosity silent
Option<string> verbosityOption = new("--verbosity", "-v")
{
    Description = "Set the verbosity level.",
};
verbosityOption.AcceptOnlyFromAmong("quiet", "minimal", "normal", "detailed", "diagnostic");
RootCommand rootCommand = new() { verbosityOption };

ParseResult parseResult = rootCommand.Parse(args);
foreach (ParseError parseError in parseResult.Errors)
{
    Console.WriteLine(parseError.Message);
}
Argument 'silent' not recognized. Must be one of:
        'quiet'
        'minimal'
        'normal'
        'detailed'
        'diagnostic'

Arguments also have expectations about how many values can be provided. Examples are provided in the section on argument arity.

Order of options and arguments

You can provide options before arguments or arguments before options on the command line. The following commands are equivalent:

dotnet add package System.CommandLine --prerelease
dotnet add package --prerelease System.CommandLine

Options can be specified in any order. The following commands are equivalent:

dotnet add package System.CommandLine --prerelease --no-restore --source https://api.nuget.org/v3/index.json
dotnet add package System.CommandLine --source https://api.nuget.org/v3/index.json --no-restore --prerelease

When there are multiple arguments, the order does matter. The following commands are not equivalent; they differ in the order of the values, which could lead to different results:

myapp argument1 argument2
myapp argument2 argument1

Aliases

In both POSIX and Windows, it's common for some commands and options to have aliases. These are usually short forms that are easier to type. Aliases can also be used for other purposes, such as to simulate case-insensitivity and to support alternate spellings of a word.

POSIX short forms typically have a single leading hyphen followed by a single character. The following commands are equivalent:

dotnet build --verbosity quiet
dotnet build -v quiet

The GNU standard recommends automatic aliases. That is, you can enter any part of a long-form command or option name and it will be accepted. This behavior would make the following command lines equivalent:

dotnet publish --output ./publish
dotnet publish --outpu ./publish
dotnet publish --outp ./publish
dotnet publish --out ./publish
dotnet publish --ou ./publish
dotnet publish --o ./publish

System.CommandLine doesn't support automatic aliases. Each alias must be specified explicitly. Both commands and options expose an Aliases property. Option has a constructor that accepts aliases as parameters, so you can define an option with multiple aliases in a single line:

Option<bool> helpOption = new("--help", ["-h", "/h", "-?", "/?"]);
Command command = new("serialize") { helpOption };
command.Aliases.Add("serialise");

We recommend that you minimize the number of option aliases that you define, and avoid defining certain aliases in particular. For more information, see Short-form aliases.

Case sensitivity

Command and option names and aliases are case-sensitive by default according to POSIX convention, and System.CommandLine follows this convention. If you want your CLI to be case insensitive, define aliases for the various casing alternatives. For example, --additional-probing-path could have aliases --Additional-Probing-Path and --ADDITIONAL-PROBING-PATH.

In some command-line tools, a difference in casing specifies a difference in function. For example, git clean -X behaves differently than git clean -x. The .NET CLI is all lowercase.

Case sensitivity does not apply to argument values for options that are based on enums. Enum names are matched regardless of casing.

The -- token

POSIX convention interprets the double-dash (--) token as an escape mechanism. Everything that follows the double-dash token is interpreted as arguments for the command. This functionality can be used to submit arguments that look like options, since it prevents them from being interpreted as options.

Suppose myapp takes a message argument, and you want the value of message to be --interactive. The following command line might give unexpected results.

myapp --interactive

If myapp doesn't have an --interactive option, the --interactive token is interpreted as an argument. But if the app does have an --interactive option, this input will be interpreted as referring to that option.

The following command line uses the double-dash token to set the value of the message argument to "--interactive":

myapp -- --interactive
      ^^

System.CommandLine supports this double-dash functionality.

Option-argument delimiters

System.CommandLine lets you use a space, '=', or ':' as the delimiter between an option name and its argument. For example, the following commands are equivalent:

dotnet build -v quiet
dotnet build -v=quiet
dotnet build -v:quiet

A POSIX convention lets you omit the delimiter when you are specifying a single-character option alias. For example, the following commands are equivalent:

myapp -vquiet
myapp -v quiet

System.CommandLine supports this syntax by default.

Argument arity

The arity of an option or command's argument is the number of values that can be passed if that option or command is specified.

Arity is expressed with a minimum value and a maximum value, as the following table illustrates:

Min Max Example validity Example
0 0 Valid: --file
Invalid: --file a.json
Invalid: --file a.json --file b.json
0 1 Valid: --flag
Valid: --flag true
Valid: --flag false
Invalid: --flag false --flag false
1 1 Valid: --file a.json
Invalid: --file
Invalid: --file a.json --file b.json
0 n Valid: --file
Valid: --file a.json
Valid: --file a.json --file b.json
1 n Valid: --file a.json
Valid: --file a.json b.json
Invalid: --file

System.CommandLine has an System.CommandLine.ArgumentArity struct for defining arity, with the following values:

  • System.CommandLine.ArgumentArity.Zero - No values allowed.
  • System.CommandLine.ArgumentArity.ZeroOrOne - May have one value, may have no values.
  • System.CommandLine.ArgumentArity.ExactlyOne - Must have one value.
  • System.CommandLine.ArgumentArity.ZeroOrMore - May have one value, multiple values, or no values.
  • System.CommandLine.ArgumentArity.OneOrMore - May have multiple values, must have at least one value.

You can explicitly set arity by using the Arity property, but in most cases that is not necessary. System.CommandLine automatically determines the argument arity based on the argument type:

Argument type Default arity
Boolean ArgumentArity.ZeroOrOne
Collection types ArgumentArity.ZeroOrMore
Everything else ArgumentArity.ExactlyOne

Option overrides

If the arity maximum is 1, System.CommandLine can still be configured to accept multiple instances of an option. In that case, the last instance of a repeated option overwrites any earlier instances. In the following example, the value 2 would be passed to the myapp command.

myapp --delay 3 --message example --delay 2

Multiple arguments

By default, when you call a command, you can repeat an option name to specify multiple arguments for an option that has maximum arity greater than one.

myapp --items one --items two --items three

To allow multiple arguments without repeating the option name, set System.CommandLine.Option.AllowMultipleArgumentsPerToken to true. This setting lets you enter the following command line.

myapp --items one two three

The same setting has a different effect if maximum argument arity is 1. It allows you to repeat an option but takes only the last value on the line. In the following example, the value three would be passed to the app.

myapp --item one --item two --item three

Option bundling

POSIX recommends that you support bundling of single-character options, also known as stacking. Bundled options are single-character option aliases specified together after a single hyphen prefix. Only the last option can specify an argument. For example, the following command lines are equivalent:

git clean -f -d -x
git clean -fdx

If an argument is provided after an option bundle, it applies to the last option in the bundle. The following command lines are equivalent:

myapp -a -b -c arg
myapp -abc arg

In both variants in this example, the argument arg would apply only to the option -c.

Boolean options (flags)

If true or false is passed for an option having a bool argument, it's parsed as expected. But an option whose argument type is bool typically doesn't require an argument to be specified. Boolean options, sometimes called "flags", typically have an arity of System.CommandLine.ArgumentArity.ZeroOrOne. The presence of the option name on the command line, with no argument following it, results in a default value of true. The absence of the option name in command-line input results in a value of false. If the myapp command prints out the value of a Boolean option named --interactive, the following input creates the following output:

myapp
myapp --interactive
myapp --interactive false
myapp --interactive true
False
True
False
True

Version option

Apps built on System.CommandLine automatically provide the version number in response to the --version option used with the root command. For example:

dotnet --version
6.0.100

Response files

A response file is a file that contains a set of tokens for a command-line app. Response files are a feature of System.CommandLine that is useful in two scenarios:

  • To invoke a command-line app by specifying input that is longer than the character limit of the terminal.
  • To invoke the same command repeatedly without retyping the whole line.

To use a response file, enter the file name prefixed by an @ sign wherever in the line you want to insert commands, options, and arguments. The .rsp file extension is a common convention, but you can use any file extension.

The following lines are equivalent:

dotnet build --no-restore --output ./build-output/
dotnet @sample1.rsp
dotnet build @sample2.rsp --output ./build-output/

Contents of sample1.rsp:

build
--no-restore
--output
./build-output/

Contents of sample2.rsp:

--no-restore

Here are syntax rules that determine how the text in a response file is interpreted:

  • Tokens are delimited by spaces. A line that contains Good morning! is treated as two tokens, Good and morning!.
  • Multiple tokens enclosed in quotes are interpreted as a single token. A line that contains "Good morning!" is treated as one token, Good morning!.
  • Any text between a # symbol and the end of the line is treated as a comment and ignored.
  • Tokens prefixed with @ can reference additional response files.
  • The response file can have multiple lines of text. The lines are concatenated and interpreted as a sequence of tokens.

Directives

System.CommandLine introduces a syntactic element called a directive represented by System.CommandLine.Directive type. The [diagram] directive is an example. When you include [diagram] after the app's name, System.CommandLine displays a diagram of the parse result instead of invoking the command-line app:

dotnet [diagram] build --no-restore --output ./build-output/
       ^-----^
[ dotnet [ build [ --no-restore <True> ] [ --output <./build-output/> ] ] ]

The purpose of directives is to provide cross-cutting functionality that can apply across command-line apps. Because directives are syntactically distinct from the app's own syntax, they can provide functionality that applies across apps.

A directive must conform to the following syntax rules:

  • It's a token on the command line that comes after the app's name but before any subcommands or options.
  • It's enclosed in square brackets.
  • It doesn't contain spaces.

An unrecognized directive is ignored without causing a parsing error.

A directive can include an argument, separated from the directive name by a colon.

The following directives are built in:

The [diagram] directive

Both users and developers might find it useful to see how an app will interpret a given input. One of the default features of a System.CommandLine app is the [diagram] directive, which lets you preview the result of parsing command input. For example:

myapp [diagram] --delay not-an-int --interactive --file filename.txt extra
![ myapp [ --delay !<not-an-int> ] [ --interactive <True> ] [ --file <filename.txt> ] *[ --fgcolor <White> ] ]   ???--> extra

In the preceding example:

  • The command (myapp), its child options, and the arguments to those options are grouped using square brackets.
  • For the option result [ --delay !<not-an-int> ], the ! indicates a parsing error. The value not-an-int for an int option can't be parsed to the expected type. The error is also flagged by ! in front of the command that contains the errored option: ![ myapp....
  • For the option result *[ --fgcolor <White> ], the option wasn't specified on the command line, so the configured default was used. White is the effective value for this option. The asterisk indicates that the value is the default.
  • ???--> points to input that wasn't matched to any of the app's commands or options.

Suggest directive

The [suggest] directive lets you search for commands when you don't know the exact command.

dotnet [suggest] buil
build
build-server
msbuild

See also