Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse command line arguments

I want to parse a set of command line arguments that look like:

-p[project file path] -s[name 1]=[value 1] ... -s[name n]=[value n]

Where there is exactly one project p and any number of settings s.

I have tried using NDesk.Options

var set = new OptionSet {
    { "p=", "the project file", v => { /* do stuff */ } },
    { "s=", "a setting", (m, v) =>  { /* do stuff */ } },
};

and this works well in most cases, but when value is a file path (even quoted) the \ causes the parser to drop everything to right. I've hacked round this by overriding the parse method on my own OptionSet class that I've inherited from NDesk.Options.OptionSet, but I was wondering if there are any libraries that can handle this kind of functionality out of the box?

UPDATE

Sorry it wasn't the \ I think it is the : anyway a set of failing examples is:

-sSetting=C:\Temp
-sSetting="C:\Temp"
-s"Setting=C:\Temp"

They all fail with OptionException Error: Found 3 option values when expecting 2.

like image 708
satnhak Avatar asked Dec 26 '22 05:12

satnhak


2 Answers

UPDATE: Update to handle colons in setting values.

OK, so here you run into one of the implicit defaults of NDesk.Options, which is that in multivalued parameters, both : and = are considered as value separators, meaning that Setting=C:\Path parses as 3 values (Setting, C, \Path) instead of your expected two.

In order to fix that, you simply have to modify the -s option definition to only consider = as a valid separator, by writing "s={=}" instead of "s=".

Original answer, when it was about backslashes.

I have used NDesk.Options, without encountering any issues with quoted paths and backslashes.

Here is my sample program:

public static void Main(string[] args)
{
    string parsedPath = null;
    Dictionary<string, string> parsedValues = new Dictionary<string, string>();
    var set = new OptionSet() 
    { 
        { "p=", "the project path", v => parsedPath = v }, 
        { "s=", "a setting", (m, v) => { parsedValues.Add(m, v); } },
    };
    set.Parse(args);
    Console.WriteLine(parsedPath ?? "<NULL>");
    foreach (var keyValuePair in parsedValues)
    {
        Console.WriteLine(keyValuePair.Key + "::::" + keyValuePair.Value);
    }
}

You will see that there is a difference between your definition and mine: p= means that the option has a required value, while your definition means that p is a boolean flag value.

I have not run with any problem concerning backslashes, either in the p setting or in the s setting. Could you try running the program with version 0.2.1 of NDesk.Options and show which values fail?

Here are some samples that I ran, which all parsed successfully:

-p=..\Path
-p..\Path
-pC:\Hello
-pHello\World
-p"Hello\World"
-s"Greeting=Hello\World"
-sGreeting="Hello\World"
-sGreeting=Hello\World
-sGreeting="Hello\My World"
-s"Greeting=Hello\My World"

Here are some parses which do produce another result that deserve mention:

-sGreeting=Hello\My World -- // This gives Greeting="Hello\My" 

Note: If that changes anything, I ran NDesk.Options with the Options.cs source code file in the project, not with the compiled DLL.

like image 146
Jean Hominal Avatar answered Jan 12 '23 01:01

Jean Hominal


I successfully used Command Line Parser Library for some time. Works well, simple, and paths with quotes are allowed.

like image 37
ken2k Avatar answered Jan 12 '23 03:01

ken2k