How to parse command line arguments

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

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

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

I 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 the path to the file (even quoted), \ causes the parser to throw everything to the right. I cracked this by overriding the parse method in my OptionSet class, which I inherited from NDesk.Options.OptionSet , but I was wondering if there are any libraries that can handle such functions out of the box?

UPDATE

Sorry it wasnโ€™t \ I think it is : in any case, a set of unsuccessful examples:

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

All of them fail with OptionException Error: Found 3 option values when expecting 2.

+4
source share
5 answers

UPDATE : update to handle colons in settings.

OK, so here you are faced with one of the implicit values โ€‹โ€‹of NDesk.Options , which is in multi-valued parameters, like : and = treated as value separators, which means that Setting=C:\Path analyzes as 3 values โ€‹โ€‹(Setting, C, \ Path) instead of the expected two.

To fix this, you just need to change the definition of the -s option to treat = as a valid delimiter by writing "s={=}" instead of "s=" .

The original answer when it came to the backslash.

I used NDesk.Options without encountering any problems with the specified tracks 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 parameter has the required value, while your definition means that p is the value of the Boolean flag.

I had no problems with backslashes, both in setting p and setting s. Could you try to run the program with version 0.2.1 of NDesk.Options and show which values โ€‹โ€‹fail?

Here are a few examples that I followed that all successfully analyzed:

 -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 of the analyzes that lead to another result that deserves mention:

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

Note. If this changes something, I ran NDesk.Options with the source code of the Options.cs file in the project, and not with the compiled DLL.

+5
source

I have successfully used the Parser library for the command line for some time. Works well, simple, and paths with quotes are allowed .

+3
source

All splitting is done for you if you use something like:

 public static void Main(string[] args) { List<string> Settings = new list Console.WriteLine("parameter qty = {0}", args.Length); for(int i = 0; i < args.Length; i++) { Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]); } 

After that, a simple set of ifs is enough to get the required action based on each argument. You can iterate over each argument in an array of arguments to find out which argument they match using string matching or regular expressions, as you prefer. For eaxmple, you can add code to the for loop:

 public static void Main(string[] args) { List<string> Settings = new List<string>(); Console.WriteLine("parameter qty = {0}", args.Length); for(int i = 0; i < args.Length; i++) { Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]); if (i>0) { // this gives you a nice iterable list of settings Setting.Add(args[i]); } } foreach(string setting in Settings) { //do the desired action } } 

Addendum: however, it will only be basic functionality (which is fine, if I, like me, are from C ++ and have to do something on my own, not so good from the point of view of the C # developer Now I understand), you will need handle the parsing of command variants yourself (as indicated in the comment /p--p or /Project= -Project= , and all variants should be processed in the code that you create). However, for a solution from the box, I would recommend: Ndesk.Options or Mono.Options Both work the same way, and I would like to use Mono.Options if portability is important.

When using, you can change your code to

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

And this, I hope, will give you the necessary functionality (an example from ndesk here at the end of the page there is even a coded usage example).

Hope this is more helpful than my previous answer for you.

+2
source

You can combine all the arguments into one line, and then you can use regular expressions:

 ((?<SkeyvaluePair>-s(?<key>[^=]+)\s*=\s*(?<value>[^-]+))|(?<PkeyvaluePair>-p(?<Pvalue>[^-]+)))* 

then split the line into groups

 var groups = new Regex(yourRegex).Match(message).Groups; 

and extract the necessary information

 var pairs = groups["keyvaluepair"].Captures.Cast<Capture>() 
0
source
 class Program { static void Main(string[] args) { string cmd = "car.exe -ip 1.18.4.156 -port 123"; string hostname = "localhost"; string port = "5505"; string[] array = cmd.Split(' '); int hostnameIndex = Array.FindIndex(array, key => key == "-ip"); int portIndex = Array.FindLastIndex(array, key => key == "-port"); if (hostnameIndex != -1) { hostname = array[hostnameIndex + 1]; } if (portIndex != -1) { port = array[portIndex + 1]; } Console.WriteLine("ip :" + hostname); Console.WriteLine("port :" + port); } } 
0
source

All Articles