คุณเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งใน Swift ได้อย่างไร


121

คุณเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งสำหรับแอปพลิเคชันบรรทัดคำสั่งใน Swift ได้อย่างไร


คำตอบ:


7

Apple ได้เปิดตัวArgumentParserไลบรารีเพื่อทำสิ่งนี้:

เรามีความยินดีที่จะประกาศArgumentParserไลบรารีโอเพนซอร์สใหม่ที่ทำให้ตรงไปตรงมา - สนุกสนานได้! - เพื่อแยกวิเคราะห์อาร์กิวเมนต์บรรทัดคำสั่งใน Swift

https://swift.org/blog/argument-parser/


ตัวแยกวิเคราะห์อาร์กิวเมนต์อย่างรวดเร็ว

https://github.com/apple/swift-argument-parser

เริ่มต้นด้วยการประกาศประเภทที่กำหนดข้อมูลที่คุณต้องการรวบรวมจากบรรทัดคำสั่ง ตกแต่งสถานที่ให้บริการเก็บไว้แต่ละคนมีหนึ่งArgumentParser's ParsableCommandห่อทรัพย์สินและประกาศความสอดคล้องกับ

ArgumentParserห้องสมุดแยกอาร์กิวเมนต์บรรทัดคำสั่งที่ instantiates ประเภทคำสั่งของคุณและจากนั้นดำเนินการกำหนดเองของคุณrun()วิธีการหรือออกพร้อมกับข้อความที่มีประโยชน์


305

ปรับปรุง 01/17/17: Updated ตัวอย่างสำหรับสวิฟท์ 3. ได้รับการเปลี่ยนชื่อเป็นProcessCommandLine


อัปเดต 30/09/2015:อัปเดตตัวอย่างเพื่อทำงานใน Swift 2


เป็นจริงไปได้ที่จะทำเช่นนี้โดยมูลนิธิหรือ และC_ARGVC_ARGC

ไลบรารีมาตรฐานของ Swift มีโครงสร้างCommandLineที่มีการStringเรียกargumentsชุด ดังนั้นคุณสามารถเปิดอาร์กิวเมนต์ดังนี้:

for argument in CommandLine.arguments {
    switch argument {
    case "arg1":
        print("first argument")

    case "arg2":
        print("second argument")

    default:
        print("an argument")
    }
}

10
@AlbinStigo Process.arguments เป็นอาร์เรย์ของสตริงอยู่แล้วไม่จำเป็นต้องสร้างใหม่
Lance

9
คำตอบที่ดีที่สุดมักไม่ใช่คำตอบที่ได้รับการยอมรับ :)
HepaKKes

5
ถ้าใครนอกจากฉันใส่ใจในกระบวนการผลิตเป็นจริงการแจงนับ
robobrobro

1
เป็นProcess.argumentsแบบเดียวกับNSProcessInfo.processInfo().arguments?
Franklin Yu

5
ในสแนปชอต Swift ล่าสุด (ไม่ว่าจะเป็นสแนปชอต 7/28 หรือสแนปชอต 7/29) Processตอนนี้วัตถุนั้นเรียกว่าCommandLineวัตถุ สิ่งนี้อาจรวมเข้าด้วยกันอย่างสมบูรณ์เมื่อ Swift 3.0 เปิดตัวอย่างเป็นทางการ
TheSoundDefense


46

ใช้ค่าคงที่ระดับด้านบนและC_ARGCC_ARGV

for i in 1..C_ARGC {
    let index = Int(i);

    let arg = String.fromCString(C_ARGV[index])
    switch arg {
    case "this":
        println("this yo");

    case "that":
        println("that yo")

    default:
        println("dunno bro")
    }
}

โปรดทราบว่าฉันใช้ช่วงของ1..C_ARGCเนื่องจากองค์ประกอบแรกของC_ARGV"อาร์เรย์" คือเส้นทางของแอปพลิเคชัน

C_ARGVตัวแปรไม่จริงอาร์เรย์ แต่ย่อยสคริปต์เช่นอาร์เรย์


4
คุณยังสามารถใช้ NSProcessInfo ได้เช่นเดียวกับที่คุณทำใน Objective-C
Jack Lawrence

3
NSProcessInfo ต้องการ Foundation คำตอบของฉันไม่ต้องการ Foundation เพียงแค่ใช้ lib มาตรฐาน lang ที่รวดเร็ว
orj

7
C_ARCGดูเหมือนจะไม่ได้รับการสนับสนุนอีกต่อไป
juandesant

2
ฉันยืนยันได้ว่า C_ARG ไม่ทำงานกับเครื่องมือเวอร์ชันล่าสุดอีกต่อไป XCode เวอร์ชัน 7.1 (7B91b)
svth

8
คุณสามารถใช้แทนProcess.argcและProcess.argumentsสำหรับสิ่งนี้แม้ว่าดูเหมือนว่าสิ่งนี้อาจกำลังเปลี่ยนไปCommandLine.argcและCommandLine.argumentsมีการเปลี่ยนแปลงล่าสุดในภาษา
TheSoundDefense

14

ใครก็ตามที่ต้องการใช้ "getopt" รุ่นเก่า (ซึ่งมีอยู่ใน Swift) สามารถใช้สิ่งนี้เป็นข้อมูลอ้างอิงได้ ฉันสร้างพอร์ต Swift ของตัวอย่าง GNU ใน C สามารถค้นหาได้ที่:

http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html

พร้อมคำอธิบายแบบเต็ม ได้รับการทดสอบและใช้งานได้อย่างสมบูรณ์ ไม่จำเป็นต้องใช้ Foundation เช่นกัน

var aFlag   = 0
var bFlag   = 0
var cValue  = String()

let pattern = "abc:"
var buffer = Array(pattern.utf8).map { Int8($0) }

while  true {
    let option = Int(getopt(C_ARGC, C_ARGV, buffer))
    if option == -1 {
        break
    }
    switch "\(UnicodeScalar(option))"
    {
    case "a":
        aFlag = 1
        println("Option -a")
    case "b":
        bFlag = 1
        println("Option -b")
    case "c":
        cValue = String.fromCString(optarg)!
        println("Option -c \(cValue)")
    case "?":
        let charOption = "\(UnicodeScalar(Int(optopt)))"
        if charOption == "c" {
            println("Option '\(charOption)' requires an argument.")
        } else {
            println("Unknown option '\(charOption)'.")
        }
        exit(1)
    default:
        abort()
    }
}
println("aflag ='\(aFlag)', bflag = '\(bFlag)' cvalue = '\(cValue)'")

for index in optind..<C_ARGC {
    println("Non-option argument '\(String.fromCString(C_ARGV[Int(index)])!)'")
}

0

คุณสามารถสร้างตัวแยกวิเคราะห์อาร์กิวเมนต์โดยใช้CommandLine.argumentsArray และเพิ่มตรรกะที่คุณต้องการ

คุณสามารถทดสอบได้ สร้างไฟล์arguments.swift

//Remember the first argument is the name of the executable
print("you passed \(CommandLine.arguments.count - 1) argument(s)")
print("And they are")
for argument in CommandLine.arguments {
    print(argument)
}

รวบรวมและเรียกใช้:

$ swiftc arguments.swift
$ ./arguments argument1 argument2 argument3

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

คุณสามารถใช้:

  • โมดูลคอนโซลของ Vapor
  • TSCUtility Argument Parser ที่ใช้โดย Swift Package manager
  • Swift Argument Parser โอเพ่นซอร์สโดย Apple

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

หากคุณสนใจนี่คือลิงค์:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.