วิธีที่ดีที่สุดในการแยกอาร์กิวเมนต์บรรทัดคำสั่งใน C #? [ปิด]


731

Main(string[] args)เมื่อมีการสร้างโปรแกรมประยุกต์คอนโซลที่ใช้พารามิเตอร์คุณสามารถใช้การขัดแย้งที่ผ่านมา

ในอดีตที่ผ่านมาฉันเพิ่งทำดัชนี / วนลูปอาร์เรย์นั้นและทำนิพจน์ปกติสองสามข้อเพื่อแยกค่า อย่างไรก็ตามเมื่อคำสั่งมีความซับซ้อนมากขึ้นการวิเคราะห์คำจะค่อนข้างน่าเกลียด

ดังนั้นฉันสนใจ:

  • ไลบรารีที่คุณใช้
  • รูปแบบที่คุณใช้

สมมติว่าคำสั่งปฏิบัติตามมาตรฐานทั่วไปเช่นคำตอบที่นี่เสมอ


การสนทนาก่อนหน้านี้การแบ่งสตริงที่มีคำสั่งพารามิเตอร์พารามิเตอร์ลงในสตริงใน c #อาจมีคำตอบบางอย่าง
gimel

1
สวัสดีขออภัยเป็นเรื่องเล็กน้อย แต่ฉันจะใช้ "การตั้งค่าแอปพลิเคชัน" เพื่อส่งผ่านอาร์กิวเมนต์ไปยังแอปพลิเคชัน ฉันพบว่ามันค่อนข้างใช้งานง่ายและไม่จำเป็นต้องเขียนการแยกอาร์กิวเมนต์ / การแยกวิเคราะห์ไฟล์และไม่จำเป็นต้องใช้ไลบรารีเพิ่มเติม msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
โทรหาฉัน Steve

44
@ call me Steve: จุดขัดแย้งของบรรทัดคำสั่งคือพวกเขาสามารถเปลี่ยนแปลงได้ต่อการโทร - คุณจะทำอย่างไรกับการตั้งค่าแอปพลิเคชัน?
reinierpost

คำตอบ:


324

ฉันขอแนะนำอย่างยิ่งให้ใช้NDesk.Options ( เอกสาร ) และ / หรือMono.Options (API เดียวกัน, เนมสเปซที่แตกต่างกัน) เช่นจากเอกสาร :

bool show_help = false;
List<string> names = new List<string> ();
int repeat = 1;

var p = new OptionSet () {
    { "n|name=", "the {NAME} of someone to greet.",
       v => names.Add (v) },
    { "r|repeat=", 
       "the number of {TIMES} to repeat the greeting.\n" + 
          "this must be an integer.",
        (int v) => repeat = v },
    { "v", "increase debug message verbosity",
       v => { if (v != null) ++verbosity; } },
    { "h|help",  "show this message and exit", 
       v => show_help = v != null },
};

List<string> extra;
try {
    extra = p.Parse (args);
}
catch (OptionException e) {
    Console.Write ("greet: ");
    Console.WriteLine (e.Message);
    Console.WriteLine ("Try `greet --help' for more information.");
    return;
}

14
NDesk.options ยอดเยี่ยม แต่ดูเหมือนจะไม่สนับสนุนแอพคอนโซลด้วยคำสั่งที่แตกต่างกันมากกว่าหนึ่งอย่าง หากคุณต้องการลองใช้ ManyConsole ที่สร้างใน NDesk.Options: nuget.org/List/Packages/ManyConsole
Frank Schwieterman

5
เมื่อฉันมีหนึ่งแอพที่มีคำสั่งที่แตกต่างกันหลายตัวฉัน "เลเยอร์" ชุดตัวเลือก ใช้ mdoc ( docs.go-mono.com/index.aspx?link=man%3amdoc%281%29 ) ซึ่งมีชุดตัวเลือก "ทั่วโลก" ( github.com/mono/monb/master/mcs/tools/ mdoc / … ) ซึ่งมอบสิทธิ์ให้ OptionSet ต่อคำสั่ง (เช่นgithub.com/mono/mono/blob/master/mcs/tools/mdoc/
......

3
NDesk ไม่ทำงานสำหรับฉัน สามารถอ่านอาร์กิวเมนต์จำนวนเต็มได้ แต่ก็ไม่เป็นสตริง ตัวแปรยังคงได้รับอาร์กิวเมนต์ (เช่น 's', 'a', ฯลฯ ) แทนค่าอาร์กิวเมนต์ (เช่น 'serverName', 'ApplicationName') รวบรวมและใช้ 'Command Line Parser Library' แทน โอเคจนถึงตอนนี้
Jay

2
@AshleyHenderson สำหรับสิ่งหนึ่งมันมีขนาดเล็กและยืดหยุ่นได้ โซลูชันส่วนใหญ่จะทำงานกับอาร์กิวเมนต์ที่มีชื่อเป็นตัวเลือกเท่านั้น (เช่นไม่สามารถทำได้git checkout master) หรืออาร์กิวเมนต์ของพวกเขาจะไม่ยืดหยุ่น (เช่นไม่สนับสนุน--foo 123= --foo=123= -f 123= -f=123และยัง-v -h= -vh)
Wernight

1
@ FrankSchwieterman ที่ควรเป็นคำตอบของตัวเอง และขอบคุณสำหรับเคล็ดลับ ManyConsole เป็นของจริงเหมาะอย่างยิ่งสำหรับฉัน
quentin-starin

197

ฉันชอบ Library Command Parser ( http://commandline.codeplex.com/ ) จริงๆ มันมีวิธีที่ง่ายและสง่างามในการตั้งค่าพารามิเตอร์ผ่านคุณสมบัติ:

class Options
{
    [Option("i", "input", Required = true, HelpText = "Input file to read.")]
    public string InputFile { get; set; }

    [Option(null, "length", HelpText = "The maximum number of bytes to process.")]
    public int MaximumLenght { get; set; }

    [Option("v", null, HelpText = "Print details during execution.")]
    public bool Verbose { get; set; }

    [HelpOption(HelpText = "Display this help screen.")]
    public string GetUsage()
    {
        var usage = new StringBuilder();
        usage.AppendLine("Quickstart Application 1.0");
        usage.AppendLine("Read user manual for usage instructions...");
        return usage.ToString();
    }
}

6
นี่คือห้องสมุดที่ฉันตั้งหลักแหล่งเช่นกัน ฉันกำลังเขียนแอปพลิเคชันสำหรับ บริษัท ขนาดใหญ่ที่ต้องดูแลรักษาเป็นเวลาหลายปี - ห้องสมุดนี้ได้รับการปรับปรุงอย่างต่อเนื่องตั้งแต่ปี 2005 ดูเหมือนว่าจะเป็นที่นิยมเขียนโดยคนที่ทำงานในชุมชน C # และได้รับใบอนุญาตในสไตล์ BSD การสนับสนุนไม่หายไป
Charles Burns

ฉันแนะนำสิ่งนี้ด้วย ปัญหาเดียวของฉันคือ: การระบุการรวมกันการโต้เถียงที่ได้รับอนุญาต (เช่นถ้ามีการโต้แย้งการย้ายจะต้องมีข้อโต้แย้งที่มาและปลายทางเช่นกัน) อาจเป็นไปได้ที่จะทำกับคุณลักษณะ แต่คุณน่าจะดีกว่าที่จะทำด้วยตรรกะตัวตรวจสอบอาร์กิวเมนต์แบบแยกส่วน
Lyndon White

1
ฉันชอบคลาสตัวเลือก ดูเหมือนว่าจะสนับสนุนพารามิเตอร์และแฟล็กที่ไม่มีชื่อเช่น--recursiveกัน
Wernight

2
ฉันเพิ่งทดสอบและฉันได้ติดตั้งตัวเลือกสำหรับใบสมัครของฉันในเวลาไม่กี่นาที มันง่ายมากที่จะใช้ห้องสมุด
Trismegistos

3
ฉันพบว่าห้องสมุดนี้เข้มงวดมากสำหรับตัวฉันเอง หากคุณต้องการชุดพิเศษคุณไม่สามารถกำหนดตัวเลือกที่จำเป็นสำหรับแต่ละชุดได้ดังนั้นต้องตรวจสอบด้วยตนเอง คุณไม่สามารถกำหนดข้อกำหนดขั้นต่ำสำหรับค่าที่ไม่มีชื่อคุณต้องตรวจสอบด้วยตนเองเช่นกัน ตัวช่วยสร้างหน้าจอยังไม่ยืดหยุ่นเลย หากพฤติกรรมของห้องสมุดไม่ตรงกับความต้องการของคุณคุณไม่สามารถเปลี่ยนแปลงอะไรได้เลย
Sergey Kostrukov

50

ห้องสมุด WPF TestApiมาพร้อมกับหนึ่งในที่อร่อยที่สุด parsers บรรทัดคำสั่งสำหรับการพัฒนา C # ฉันขอแนะนำให้ดูจากบล็อกของ Ivo Manolov บน API :

// EXAMPLE #2:
// Sample for parsing the following command-line:
// Test.exe /verbose /runId=10
// This sample declares a class in which the strongly-
// typed arguments are populated
public class CommandLineArguments
{
   bool? Verbose { get; set; }
   int? RunId { get; set; }
}

CommandLineArguments a = new CommandLineArguments();
CommandLineParser.ParseArguments(args, a);

19
+1 การแยกวิเคราะห์บรรทัดคำสั่งเป็นสิ่งที่ควรมาจากผู้จัดจำหน่าย (เช่น Microsoft) แทนที่จะใช้เครื่องมือของบุคคลที่สามแม้ว่าการสนับสนุนของผู้ขายจะมาในลักษณะที่เป็นรูปธรรม
Joel Coehoorn

2
ที่กล่าวว่าคำตอบที่ยอมรับ (ขาวดำ) เป็นสิ่งที่ดีที่สุดต่อไป
Joel Coehoorn

6
@ Joel ส่วนสำคัญที่การแยกบรรทัดคำสั่งต้องมาจากผู้ขายหรือไม่ คุณมีเหตุผลอะไร
greenoldman

3
@marcias: ฉันคิดว่าเขาหมายความว่ามันควรจะเป็นนอกกล่อง ... เหมือนหลายสิ่งหลายอย่าง :)
user7116

ห้องสมุดมีขนาดใหญ่มาก! มีมากขึ้นกว่าที่ฉันต้อง ...
Riri

24

2
ตัวเลือก NDesk มี API ที่ดีมาก
user35149

2
ฉันจะเพิ่มการลงคะแนนอีกครั้งสำหรับ NDesk มันทำงานได้ดีไม่รบกวนและมีการบันทึกไว้อย่างดี
Terence

1
Mono.GetOptions เก่ามาก NDesk.Options นั้นดีกว่ามาก (หรือ Mono.Options หากคุณต้องการมันเป็นคลาสเดียวกันที่นี่: anonsvn.mono-project.com/source/trunk/mcs/class/Mono.Options/ )
Matt Enright

7
@Adam Oren: คำตอบของฉันคือ 1 ปีและ 1 เดือน! โครงสร้างของลำตัว mono ถูกปรับโครงสร้างใหม่ ตอนนี้รหัสนั้นถูกวางไว้ที่anonsvn.mono-project.com/viewvc/branches/mono-2-2/mcs/class/…
abatishchev

6
@Tormod: Mono.GetOptions ซึ่งล้าสมัยไม่ใช่ Mono.Options Mono.Options ยังคงอยู่
กรกฎาคม

14

ดูเหมือนว่าทุกคนมีตัวแยกบรรทัดคำสั่งสำหรับสัตว์เลี้ยงของตัวเองฉันคิดว่าฉันควรเพิ่มการเพิ่มเช่นกัน :)

http://bizark.codeplex.com/

ไลบรารีนี้มีตัวแยกวิเคราะห์บรรทัดคำสั่งที่จะเริ่มต้นชั้นเรียนด้วยค่าจากบรรทัดคำสั่ง มันมีฟีเจอร์มากมาย (ฉันสร้างมันมาหลายปีแล้ว)

จากเอกสาร ...

การแยกวิเคราะห์บรรทัดคำสั่งในกรอบงาน BizArk มีคุณสมบัติที่สำคัญเหล่านี้:

  • การกำหนดค่าเริ่มต้นอัตโนมัติ:คุณสมบัติคลาสจะถูกตั้งค่าโดยอัตโนมัติตามอาร์กิวเมนต์บรรทัดคำสั่ง
  • คุณสมบัติเริ่มต้น:ส่งค่าโดยไม่ระบุชื่อคุณสมบัติ
  • การแปลงค่า:ใช้คลาส ConvertEx ที่ทรงพลังรวมอยู่ใน BizArk เพื่อแปลงค่าให้เป็นประเภทที่เหมาะสม
  • ธงบูลีน:ธงสามารถระบุได้โดยใช้อาร์กิวเมนต์ (เช่น, / b สำหรับจริงและ / b- สำหรับเท็จ) หรือโดยการเพิ่มค่าจริง / เท็จ, ใช่ / ไม่ใช่ ฯลฯ
  • อาร์กิวเมนต์ของอาร์เรย์:เพียงเพิ่มค่าหลายค่าหลังจากชื่อบรรทัดคำสั่งเพื่อตั้งค่าคุณสมบัติที่กำหนดเป็นอาร์เรย์ ตัวอย่าง / x 1 2 3 จะเติม x ด้วยอาร์เรย์ {1, 2, 3} (สมมติว่า x ถูกกำหนดเป็นอาร์เรย์ของจำนวนเต็ม)
  • นามแฝงบรรทัดคำสั่ง:คุณสมบัติสามารถรองรับนามแฝงบรรทัดคำสั่งหลายรายการได้ ตัวอย่างเช่นช่วยใช้นามแฝง?
  • การจดจำชื่อบางส่วน:คุณไม่จำเป็นต้องสะกดชื่อเต็มหรือนามแฝงเพียงสะกดให้ตัวแยกวิเคราะห์เพียงพอที่จะแยกแยะคุณสมบัติ / นามแฝงจากชื่ออื่น
  • รองรับ ClickOnce:สามารถเริ่มต้นคุณสมบัติได้แม้ว่าจะระบุเป็นสตริงการสืบค้นใน URL สำหรับแอปพลิเคชันที่ใช้งาน ClickOnce วิธีการเริ่มต้นบรรทัดคำสั่งจะตรวจสอบว่ามันทำงานเป็น ClickOnce หรือไม่เพื่อให้รหัสของคุณไม่จำเป็นต้องเปลี่ยนเมื่อใช้งาน
  • สร้าง / โดยอัตโนมัติ ช่วย:รวมถึงการจัดรูปแบบที่ดีซึ่งคำนึงถึงความกว้างของคอนโซล
  • โหลด / บันทึกอาร์กิวเมนต์ของบรรทัดคำสั่งไปยังไฟล์:สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณมีชุดอาร์กิวเมนต์บรรทัดคำสั่งขนาดใหญ่และซับซ้อนหลายชุดที่คุณต้องการเรียกใช้หลายครั้ง

2
ฉันพบตัวแยกวิเคราะห์บรรทัดคำสั่งของ BizArk ง่ายกว่าและคล่องแคล่วกว่าคนอื่น ๆ แนะนำเป็นอย่างยิ่ง!
Boris Modylevsky


9

CLAP (ตัวแยกวิเคราะห์อาร์กิวเมนต์บรรทัดคำสั่ง) มี API ที่ใช้งานได้และมีการบันทึกไว้อย่างน่าอัศจรรย์ คุณสร้างวิธีการใส่คำอธิบายประกอบพารามิเตอร์ https://github.com/adrianaisemberg/CLAP


2
มันง่ายมากที่จะใช้และเว็บไซต์ของพวกเขาหิน อย่างไรก็ตามไวยากรณ์ของพวกเขาไม่ง่ายมาก: myapp myverb -argname argvalue(ต้องมี-argname) หรือmyapp -help(ปกติ--help)
Wernight

@Wernight คุณสามารถใช้พารามิเตอร์ IsDefault บน Verb ทำเช่นนั้นได้ ฉันไม่พบการสนับสนุนสำหรับพารามิเตอร์ตำแหน่ง แต่ฉันใช้พารามิเตอร์ตำแหน่งเท่านั้นเมื่อฉันแยกวิเคราะห์บรรทัดคำสั่งด้วยตัวเอง การใช้อาร์กิวเมนต์ที่กำหนดชื่อแล้วตามด้วยค่า IMHO นั้นชัดเจนขึ้น
Loudenvier

5

มีวิธีแก้ไขปัญหานี้มากมาย เพื่อความสมบูรณ์และเพื่อให้ทางเลือกถ้ามีคนปรารถนาฉันเพิ่มคำตอบนี้สำหรับสองชั้นที่มีประโยชน์ในของฉันรหัสห้องสมุด Google

แรกคือ ArgumentList ซึ่งรับผิดชอบเฉพาะสำหรับการแยกพารามิเตอร์บรรทัดคำสั่ง มันรวบรวมคู่ค่าชื่อที่กำหนดโดยสวิตช์ '/ x: y' หรือ '-x = y' และยังรวบรวมรายการของรายการ 'ไม่มีชื่อ' มันเป็นพื้นฐานการใช้งานที่ถูกกล่าวถึงที่นี่ , ดูชั้นเรียนที่นี่

ส่วนที่สองของนี้คือCommandInterpreterซึ่งสร้างแอปพลิเคชันบรรทัดคำสั่งที่ใช้งานได้อย่างสมบูรณ์จากคลาส. Net ของคุณ ตัวอย่างเช่น:

using CSharpTest.Net.Commands;
static class Program
{
    static void Main(string[] args)
    {
        new CommandInterpreter(new Commands()).Run(args);
    }
    //example ‘Commands’ class:
    class Commands
    {
        public int SomeValue { get; set; }
        public void DoSomething(string svalue, int ivalue)
        { ... }

ด้วยโค้ดตัวอย่างข้างต้นคุณสามารถเรียกใช้ต่อไปนี้:

Program.exe DoSomething "ค่าสตริง" 5

-- หรือ --

Program.exe dosomething / ivalue = 5 -svalue: "ค่าสตริง"

มันง่ายอย่างนั้นหรือซับซ้อนตามที่คุณต้องการ คุณสามารถดูซอร์สโค้ด , ดูความช่วยเหลือหรือดาวน์โหลดไบนารี


4

ฉันชอบอันนั้นเพราะคุณสามารถ "กำหนดกฎ" สำหรับข้อโต้แย้งที่จำเป็นหรือไม่ ...

หรือถ้าคุณเป็นคนที่ใช้ระบบปฏิบัติการ Unix คุณอาจชอบพอร์ตGNU Getopt .NET


4

คุณอาจชอบRug.Cmdของฉันคนหนึ่ง

ตัวแยกอาร์กิวเมนต์บรรทัดคำสั่งที่ใช้งานง่ายและขยายได้ จับ: Bool, บวก / ลบ, สตริง, รายการสตริง, CSV, การแจงนับ

สร้างขึ้นใน '/?' โหมดช่วยเหลือ

สร้างขึ้นใน '/ ?? และโหมดตัวสร้างเอกสาร '/? D'

static void Main(string[] args) 
{            
    // create the argument parser
    ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing");

    // create the argument for a string
    StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments");

    // add the argument to the parser 
    parser.Add("/", "String", StringArg);

    // parse arguemnts
    parser.Parse(args);

    // did the parser detect a /? argument 
    if (parser.HelpMode == false) 
    {
        // was the string argument defined 
        if (StringArg.Defined == true)
        {
            // write its value
            RC.WriteLine("String argument was defined");
            RC.WriteLine(StringArg.Value);
        }
    }
}

แก้ไข: นี่เป็นโครงการของฉันและไม่ควรมองว่าคำตอบนี้เป็นการรับรองจากบุคคลที่สาม ที่กล่าวว่าฉันจะใช้มันสำหรับทุกโปรแกรมบรรทัดคำสั่งตามที่ฉันเขียนมันเป็นโอเพนซอร์สและมันเป็นความหวังของฉันที่คนอื่นอาจได้รับประโยชน์จากมัน


เพียงแค่ FYI ที่คุณควรปฏิเสธความรับผิดชอบเล็กน้อยที่คุณมีส่วนเกี่ยวข้องกับโครงการ Rug.Cmd (ตามที่กล่าวไว้ในคำถามที่พบบ่อย): stackoverflow.com/faq#promotion - ไม่ใช่เรื่องใหญ่เพราะคุณกำลังโปรโมต โครงการแหล่งที่มา แต่ก็ยังดีที่จะเพิ่มข้อจำกัดความรับผิดชอบ;) +1 โดยวิธี ... ดูดีมาก
เจสันลง

ไชโยที่ชี้ให้เห็นว่าและขอบคุณสำหรับ +1 ฉันจะทำให้แน่ใจว่าฉันชัดเจนยิ่งขึ้นเกี่ยวกับการเป็นพันธมิตรของฉัน
Phill Tew

ไม่ต้องกังวล ... มีบางคนที่ติดอยู่ที่นั่นสำหรับสิ่งประเภทนี้ (ฉันไม่ได้เป็นหนึ่งในนั้น) ดังนั้นฉันจึงอยากให้คนอื่น อีกครั้งมักจะไม่เป็นปัญหาสำหรับโครงการโอเพ่นซอร์ส ส่วนใหญ่เป็นการหยุดผู้คนจากการแนะนำการส่งสแปมสำหรับผลิตภัณฑ์ที่ชำระเงิน
เจสันลง

3

มีตัวแยกวิเคราะห์อาร์กิวเมนต์บรรทัดคำสั่งที่http://www.codeplex.com/commonlibrarynet

มันสามารถแยกอาร์กิวเมนต์โดยใช้
1. คุณลักษณะ
2. เรียกชัดเจน
3. บรรทัดเดียวของหลาย ๆ อาร์กิวเมนต์หรืออาร์เรย์สตริง

สามารถจัดการสิ่งต่าง ๆ ดังต่อไปนี้:

- config : Qa - startdate : $ { วันนี้ } - ภูมิภาค : การตั้งค่า 'นิวยอร์ก'

มันใช้งานง่ายมาก


2

นี่คือตัวจัดการที่ฉันเขียนตามOptionsคลาสNovell

อันนี้มีวัตถุประสงค์เพื่อการใช้งานคอนโซลที่รัน while (input !="exit")สไตล์วน, คอนโซลแบบโต้ตอบเช่นคอนโซล FTP เป็นต้น

ตัวอย่างการใช้งาน:

static void Main(string[] args)
{
    // Setup
    CommandHandler handler = new CommandHandler();
    CommandOptions options = new CommandOptions();

    // Add some commands. Use the v syntax for passing arguments
    options.Add("show", handler.Show)
        .Add("connect", v => handler.Connect(v))
        .Add("dir", handler.Dir);

    // Read lines
    System.Console.Write(">");
    string input = System.Console.ReadLine();

    while (input != "quit" && input != "exit")
    {
        if (input == "cls" || input == "clear")
        {
            System.Console.Clear();
        }
        else
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (options.Parse(input))
                {
                    System.Console.WriteLine(handler.OutputMessage);
                }
                else
                {
                    System.Console.WriteLine("I didn't understand that command");
                }

            }

        }

        System.Console.Write(">");
        input = System.Console.ReadLine();
    }
}

และแหล่งที่มา:

/// <summary>
/// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options).
/// </summary>
public class CommandOptions
{
    private Dictionary<string, Action<string[]>> _actions;
    private Dictionary<string, Action> _actionsNoParams;

    /// <summary>
    /// Initializes a new instance of the <see cref="CommandOptions"/> class.
    /// </summary>
    public CommandOptions()
    {
        _actions = new Dictionary<string, Action<string[]>>();
        _actionsNoParams = new Dictionary<string, Action>();
    }

    /// <summary>
    /// Adds a command option and an action to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action action)
    {
        _actionsNoParams.Add(name, action);
        return this;
    }

    /// <summary>
    /// Adds a command option and an action (with parameter) to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate that has one parameter - string[] args.</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action<string[]> action)
    {
        _actions.Add(name, action);
        return this;
    }

    /// <summary>
    /// Parses the text command and calls any actions associated with the command.
    /// </summary>
    /// <param name="command">The text command, e.g "show databases"</param>
    public bool Parse(string command)
    {
        if (command.IndexOf(" ") == -1)
        {
            // No params
            foreach (string key in _actionsNoParams.Keys)
            {
                if (command == key)
                {
                    _actionsNoParams[key].Invoke();
                    return true;
                }
            }
        }
        else
        {
            // Params
            foreach (string key in _actions.Keys)
            {
                if (command.StartsWith(key) && command.Length > key.Length)
                {

                    string options = command.Substring(key.Length);
                    options = options.Trim();
                    string[] parts = options.Split(' ');
                    _actions[key].Invoke(parts);
                    return true;
                }
            }
        }

        return false;
    }
}

2

รายการโปรดส่วนตัวของฉันคือhttp://www.codeproject.com/KB/recipes/plossum_commandline.aspxโดย Peter Palotas:

[CommandLineManager(ApplicationName="Hello World",
    Copyright="Copyright (c) Peter Palotas")]
class Options
{
   [CommandLineOption(Description="Displays this help text")]
   public bool Help = false;

   [CommandLineOption(Description = "Specifies the input file", MinOccurs=1)]
   public string Name
   {
      get { return mName; }
      set
      {
         if (String.IsNullOrEmpty(value))
            throw new InvalidOptionValueException(
                "The name must not be empty", false);
         mName = value;
      }
   }

   private string mName;
}

2

ฉันเพิ่งเจอการใช้บรรทัดคำสั่งการแยกวิเคราะห์ FubuCore ฉันชอบมันมากเหตุผล:

  • มันใช้งานง่าย - แม้ว่าฉันจะไม่พบเอกสารประกอบ แต่โซลูชัน FubuCore ยังมีโครงการที่มีชุดทดสอบหน่วยที่ดีซึ่งพูดถึงการใช้งานได้มากกว่าเอกสารใด ๆ
  • มันมีการออกแบบเชิงวัตถุที่ดีไม่มีการทำซ้ำรหัสหรือสิ่งอื่น ๆ ที่ฉันเคยมีในแอพบรรทัดคำสั่งของฉัน
  • เป็นการประกาศ: โดยทั่วไปคุณเขียนคลาสสำหรับคำสั่งและชุดพารามิเตอร์และตกแต่งด้วยแอททริบิวเพื่อตั้งค่าตัวเลือกต่าง ๆ (เช่นชื่อคำอธิบายบังคับ / ไม่จำเป็น)
  • ห้องสมุดยังพิมพ์กราฟการใช้งานที่ดีตามคำจำกัดความเหล่านี้

ด้านล่างเป็นตัวอย่างง่ายๆเกี่ยวกับวิธีใช้สิ่งนี้ เพื่อแสดงการใช้งานฉันได้เขียนโปรแกรมอรรถประโยชน์ที่มีสองคำสั่ง: - เพิ่ม (เพิ่มวัตถุในรายการ - วัตถุประกอบด้วยชื่อ (สตริง), ค่า (int) และธงบูลีน) - รายการ (รายการ วัตถุที่เพิ่มทั้งหมดในปัจจุบัน)

ก่อนอื่นฉันเขียนคลาส Command สำหรับคำสั่ง 'add':

[Usage("add", "Adds an object to the list")]
[CommandDescription("Add object", Name = "add")]
public class AddCommand : FubuCommand<CommandInput>
{
    public override bool Execute(CommandInput input)
    {
        State.Objects.Add(input); // add the new object to an in-memory collection

        return true;
    }
}

คำสั่งนี้ใช้อินสแตนซ์ CommandInput เป็นพารามิเตอร์ดังนั้นฉันจึงกำหนดว่าต่อไป:

public class CommandInput
{
    [RequiredUsage("add"), Description("The name of the object to add")]
    public string ObjectName { get; set; }

    [ValidUsage("add")]
    [Description("The value of the object to add")]
    public int ObjectValue { get; set; }

    [Description("Multiply the value by -1")]
    [ValidUsage("add")]
    [FlagAlias("nv")]
    public bool NegateValueFlag { get; set; }
}

คำสั่งถัดไปคือ 'รายการ' ซึ่งจะดำเนินการดังนี้:

[Usage("list", "List the objects we have so far")]
[CommandDescription("List objects", Name = "list")]
public class ListCommand : FubuCommand<NullInput>
{
    public override bool Execute(NullInput input)
    {
        State.Objects.ForEach(Console.WriteLine);

        return false;
    }
}

คำสั่ง 'list' ไม่มีพารามิเตอร์ดังนั้นฉันจึงกำหนดคลาส NullInput สำหรับสิ่งนี้:

public class NullInput { }

สิ่งที่เหลืออยู่ในตอนนี้คือการเชื่อมโยงสิ่งนี้ในวิธีการหลัก () เช่นนี้:

    static void Main(string[] args)
    {
        var factory = new CommandFactory();
        factory.RegisterCommands(typeof(Program).Assembly);

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

โปรแกรมทำงานตามที่คาดไว้พิมพ์คำแนะนำเกี่ยวกับการใช้งานที่ถูกต้องในกรณีที่คำสั่งใด ๆ ไม่ถูกต้อง:

  ------------------------
    Available commands:
  ------------------------
     add -> Add object
    list -> List objects
  ------------------------

และตัวอย่างการใช้คำสั่ง 'เพิ่ม':

Usages for 'add' (Add object)
  add <objectname> [-nv]

  -------------------------------------------------
    Arguments
  -------------------------------------------------
     objectname -> The name of the object to add
    objectvalue -> The value of the object to add
  -------------------------------------------------

  -------------------------------------
    Flags
  -------------------------------------
    [-nv] -> Multiply the value by -1
  -------------------------------------

2

Commandlets Powershell

การแยกวิเคราะห์ทำโดย powershell ตามคุณลักษณะที่ระบุบน commandlets สนับสนุนการตรวจสอบความถูกต้องชุดพารามิเตอร์ pipelining การรายงานข้อผิดพลาดความช่วยเหลือและสิ่งที่ดีที่สุดของออบเจ็กต์. NET ทั้งหมดที่ส่งคืนเพื่อใช้ใน commandlets อื่น

ลิงค์คู่ฉันพบว่ามีประโยชน์ในการเริ่มต้น:


2

C # CLIเป็นอาร์กิวเมนต์บรรทัดคำสั่งที่ง่ายมากในการแยกวิเคราะห์ไลบรารีที่ฉันเขียน มันเป็นเอกสารที่ดีและโอเพนซอร์ส


มีเอกสารดีไหม เอกสารอยู่ที่ไหน
Suhas

มีเอกสารภายใน (เช่นใน codebase) เช่นเดียวกับเอกสารภายนอก (ดูReadme.mkdไฟล์ในDocumentationโฟลเดอร์)
เบอร์นาร์ด

ตกลงฉันแสดงความคิดเห็นอย่างเร่งรีบ อาจเป็นเพราะคุณสามารถย้ายโครงการของคุณไปที่ GitHub และเอกสารของคุณจะเริ่มปรากฏบนหน้าแรกโดยอัตโนมัติ
Suhas

1

Genghis Command Line Parser อาจจะล้าสมัยนิดหน่อย แต่มันมีคุณสมบัติที่สมบูรณ์มากและใช้งานได้ดีสำหรับฉัน


เศร้า แต่ตัวแยกวิเคราะห์บรรทัดคำสั่งของ Genghis ไม่มีเอกสารใด ๆ
okigan

หากคุณดูที่แหล่งที่มามีตัวอย่างที่แสดงตัวเลือกการใช้งาน genghis.codeplex.com/SourceControl/changeset/view/9491#73699
devdimi

0

ฉันขอแนะนำให้มาเปิดห้องสมุดCSharpOptParse มันแยกวิเคราะห์บรรทัดคำสั่งและ hydrates วัตถุ. NET ที่ผู้ใช้กำหนดด้วยอินพุตบรรทัดคำสั่ง ฉันมักจะหันไปที่ห้องสมุดนี้เสมอเมื่อเขียนแอปพลิเคชันคอนโซล C #



0

คลาส ad hoc ที่ใช้งานง่ายมากสำหรับการแยกวิเคราะห์บรรทัดคำสั่งที่รองรับอาร์กิวเมนต์เริ่มต้น

class CommandLineArgs
{
    public static CommandLineArgs I
    {
        get
        {
            return m_instance;
        }
    }

    public  string argAsString( string argName )
    {
        if (m_args.ContainsKey(argName)) {
            return m_args[argName];
        }
        else return "";
    }

    public long argAsLong(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToInt64(m_args[argName]);
        }
        else return 0;
    }

    public double argAsDouble(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToDouble(m_args[argName]);
        }
        else return 0;
    }

    public void parseArgs(string[] args, string defaultArgs )
    {
        m_args = new Dictionary<string, string>();
        parseDefaults(defaultArgs );

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private void parseDefaults(string defaultArgs )
    {
        if ( defaultArgs == "" ) return;
        string[] args = defaultArgs.Split(';');

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private Dictionary<string, string> m_args = null;
    static readonly CommandLineArgs m_instance = new CommandLineArgs();
}

class Program
{
    static void Main(string[] args)
    {
        CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12");
        Console.WriteLine("Arg myStringArg  : '{0}' ", CommandLineArgs.I.argAsString("myStringArg"));
        Console.WriteLine("Arg someLong     : '{0}' ", CommandLineArgs.I.argAsLong("someLong"));
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.