The following simple Program.cs
expects a single argument for a defined root command:
using System.CommandLine;
var inputArgument = new Argument<string>(
name: "--input",
description: "input any value and print it out");
var rootCommand = new RootCommand();
rootCommand.AddArgument(inputArgument);
rootCommand.SetHandler((inputArgumentValue) =>
{
Console.WriteLine($"{inputArgumentValue}");
}, inputArgument);
rootCommand.Invoke(args);
I would expect calling this with the following parameter: --input "Hello World"
to print out Hello World in the shell. However I get the following error:
Unrecognized command or argument 'Hello World'.
When I replace the Argument class with the Option, it works as expected:
using System.CommandLine;
var inputArgument = new Option<string>(
name: "--input",
description: "input any value and print it out");
var rootCommand = new RootCommand();
rootCommand.AddOption(inputArgument);
rootCommand.SetHandler((inputArgumentValue) =>
{
Console.WriteLine($"{inputArgumentValue}");
}, inputArgument);
rootCommand.Invoke(args);
What did I misunderstand about the Argument
class? Why can I not pass an argument with a value to it?
I want to use the argument class instead of options due to its other properties. I am using .NET 6.0 and System.CommandLine version 2.0.0-beta4.22272.1
Check out the Command-line syntax overview for System.CommandLine
docs.
It defines options as:
An option is a named parameter that can be passed to a command. The POSIX convention is to prefix the option name with two hyphens (
--
).
And arguments as:
An argument is a value passed to an option or a command.
So basically argument is a nameless positional parameter passed to command or option, i.e. for your first snippet valid call would be:
appName "Hello World"
You can of course add 2 arguments:
var inputArgument = new Argument<string>(
name: "input",
description: "input any value and print it out");
var inputArgument2 = new Argument<string>(
name: "input2",
description: "input any value and print it out");
var rootCommand = new RootCommand();
rootCommand.AddArgument(inputArgument);
rootCommand.AddArgument(inputArgument2);
rootCommand.SetHandler((inputArgumentValue, inputArgumentValue2) =>
{
Console.WriteLine($"{inputArgumentValue} - {inputArgumentValue2}");
}, inputArgument, inputArgument2);
Then your appName --input "Hello World"
invocation will result in handler getting 2 values --input
for inputArgumentValue
and "Hello World"
for inputArgumentValue2
.
But I would argue using Option<string>
(the second snippet) should be more correct approach (also it will allow passing values delimited with =
: appName --input="Hello World"
).