Wie greifen Sie in Swift auf Befehlszeilenargumente zu?

Antworten:

7

Apple hat die ArgumentParserBibliothek dafür veröffentlicht:

Wir freuen uns, Ihnen ArgumentParsereine neue Open-Source-Bibliothek vorstellen zu können , die es unkompliziert macht - und sogar Spaß macht! - um Befehlszeilenargumente in Swift zu analysieren.

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


Schneller Argument-Parser

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

Deklarieren Sie zunächst einen Typ, der die Informationen definiert, die Sie über die Befehlszeile erfassen müssen. Dekorieren Sie jede gespeicherte Eigenschaft mit einem der ArgumentParserEigenschafts-Wrapper und erklären Sie die Konformität mit ParsableCommand.

Die ArgumentParserBibliothek analysiert die Befehlszeilenargumente, instanziiert Ihren Befehlstyp und führt dann entweder Ihre benutzerdefinierte run()Methode aus oder beendet sie mit einer nützlichen Nachricht.

pkamb
quelle
305

Update 17.01.17: Das Beispiel für Swift 3 Processwurde aktualisiert und in umbenannt CommandLine.


Update 30.09.2015: Das Beispiel wurde aktualisiert, um in Swift 2 zu funktionieren.


Es ist tatsächlich möglich, dies ohne Foundation oder C_ARGV und zu tun C_ARGC.

Die Swift-Standardbibliothek enthält eine Struktur CommandLinemit einer Sammlung von Strings namens arguments. Sie können also folgende Argumente aktivieren:

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

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

    default:
        print("an argument")
    }
}
Mark Adams
quelle
10
@AlbinStigo Process.arguments ist bereits ein Array von Zeichenfolgen, es ist nicht erforderlich, eine neue zu erstellen.
Lance
9
Wie fast immer ist die beste Antwort nicht die akzeptierte. :)
HepaKKes
5
Wenn sich jemand außer mir darum kümmert, ist Process tatsächlich eine Aufzählung .
Robobrobro
1
Ist Process.argumentsdas gleiche wie NSProcessInfo.processInfo().arguments?
Franklin Yu
5
In den neuesten Swift-Snapshots (entweder der 7/28-Snapshot oder der 7/29-Snapshot) wird das ProcessObjekt jetzt als CommandLineObjekt bezeichnet. Dies wird wahrscheinlich vollständig integriert sein, sobald Swift 3.0 offiziell veröffentlicht ist.
TheSoundDefense
57

Verwenden Sie in Swift 3 CommandLineEnum anstelle vonProcess

So:

let arguments = CommandLine.arguments
Maciek Czarnik
quelle
46

Verwenden Sie die Konstanten der obersten Ebene C_ARGCund C_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")
    }
}

Beachten Sie, dass ich den Bereich von verwende, 1..C_ARGCda das erste Element des C_ARGV"Arrays" der Pfad der Anwendung ist.

Die C_ARGVVariable ist eigentlich kein Array, kann aber wie ein Array subskriptiert werden.

orj
quelle
4
Sie können auch NSProcessInfo verwenden, genau wie in Objective-C.
Jack Lawrence
3
NSProcessInfo erfordert Foundation. Meine Antwort erfordert keine Foundation. Verwendet nur Swift Lang Standard Lib.
Orj
7
C_ARCGscheint nicht mehr unterstützt zu werden.
Juandesant
2
Ich kann bestätigen, dass C_ARG nicht mehr mit der neuesten Version der Tools, XCode Version 7.1 (7B91b), funktioniert.
Svth
8
Sie können stattdessen Process.argcund Process.argumentsdafür verwenden, obwohl es so aussieht, als würde sich dies zu CommandLine.argcund CommandLine.argumentsmit den letzten Änderungen an der Sprache ändern.
TheSoundDefense
14

Jeder, der das alte "getopt" (das in Swift verfügbar ist) verwenden möchte, kann dies als Referenz verwenden. Ich habe einen Swift-Port des GNU-Beispiels in C erstellt, das unter folgender Adresse zu finden ist:

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

mit einer vollständigen Beschreibung. Es ist getestet und voll funktionsfähig. Es erfordert auch keine 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)])!)'")
}
Michele Dall'Agata
quelle
0

Sie können mithilfe des CommandLine.argumentsArrays einen Argumentparser erstellen und eine beliebige Logik hinzufügen.

Sie können es testen. Erstellen Sie eine Dateiarguments.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)
}

Kompilieren Sie es und führen Sie es aus:

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

Das Problem beim Erstellen eines eigenen Argumentparsers besteht darin, alle Befehlszeilenargumentkonventionen zu berücksichtigen. Ich würde empfehlen, einen vorhandenen Argument-Parser zu verwenden.

Du könntest benutzen:

  • Vapor's Console-Modul
  • TSCUtility Argument Parser, der vom Swift Package Manager verwendet wird
  • Der von Apple Open Source bezogene Swift Argument Parser

Ich habe darüber geschrieben, wie man Befehlszeilen-Tools für alle drei erstellt. Sie sollten sie ausprobieren und entscheiden, welcher Stil am besten zu Ihnen passt.

Wenn Sie hier interessiert sind, sind die Links:

Derik Ramirez
quelle