commandline icon indicating copy to clipboard operation
commandline copied to clipboard

Handling argument values that start with dash

Open gioccher opened this issue 9 years ago • 2 comments

I'm trying to parse a command line that looks like this: program.exe --arg "-test" but it returns this error Option 't' is unknown.

using System;
using System.Linq;
using CommandLine;

class Program
{
    static void Main(string[] args)
    {
        var cmdLine = Parser.Default.ParseArguments<Options>(args);
        if (cmdLine.Errors.Any())
            Console.Error.WriteLine(cmdLine.Errors);
    }
}

class Options
{
    [Option]
    public string Arg { get; set; }
}

gioccher avatar Mar 24 '15 21:03 gioccher

Well there's a strange little oddity. Technically, that's "expected behavior" based on the argument array that you're passing in to the parser, but since one of the primary uses of this library is to, well, parse arguments, it's probably worth devising a way of handling this situation.

See, .Net already has its own argument parser, except all it does is turn a single string (the arguments past program.exe) into a string array (args). It's the same code that turns program.exe --arg "multi word argument" into an array with two elements. And most importantly, it drops the quotes in the process. If you print out each argument in args, you'll notice that you get identical results whether you call program.exe --arg -test or program.exe --arg "-test" since they're already separated out into arguments by .Net (or more likely by your shell).

In general, this problem cannot be solved if you continue to use the arguments provided by the Main function since it strips out those quotes which are critical to differentiate between a literal and an argument. The best alternative would be to provide a function to manually tokenize Environment.CommandLine.

In this specific case it's possible to solve the issue using the "double dash" setting. This causes all values after a -- token to be consumed as literals even if they contain dashes (like -test).

The code looks like this:

var parser = new Parser (settings => {
    settings.EnableDashDash = true;
});
var cmdLine = parser.ParseArguments<Options> (args);

And when you call the executable with a value with a dash, use this:

program.exe --arg -- -test

arg has to be the last argument, of course, so it's a bit inconvenient but in cases where no values begin with a dash you don't need to do anything special (program.exe --arg myvalue)

nemec avatar Mar 24 '15 23:03 nemec

It is also possible to demand some sort of escaping for starting dash and process it internally

Litee avatar Apr 04 '15 18:04 Litee