Jak uzyskać dostęp do argumentów wiersza poleceń w Swift?

Odpowiedzi:

7

Firma Apple udostępniła ArgumentParserbibliotekę właśnie w tym celu:

Z przyjemnością ogłaszamy ArgumentParser, że nowa biblioteka open-source jest prosta - a nawet przyjemna! - analizować argumenty wiersza poleceń w języku Swift.

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


Swift Argument Parser

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

Rozpocznij od zadeklarowania typu, który definiuje informacje, które musisz zebrać z wiersza poleceń. Udekoruj każdą przechowywaną właściwość jednym z ArgumentParseropakowań właściwości i zadeklaruj zgodność z ParsableCommand.

ArgumentParserBiblioteka analizuje argumenty wiersza polecenia, instancję typ polecenia, a następnie albo wykonuje niestandardową run()metodę lub wychodzi z przydatnych wiadomości.

pkamb
źródło
305

Aktualizacja 17.01.2017: Zaktualizowano nazwę przykładu Swift 3. Processna CommandLine.


Aktualizacja 30.09.2015: Zaktualizowano przykład, aby działał w Swift 2.


W rzeczywistości można to zrobić bez Foundation lub C_ARGV i C_ARGC.

Biblioteka standardowa Swift zawiera strukturę, CommandLinektóra ma kolekcję Stringplików nazwanych arguments. Możesz więc włączyć takie argumenty:

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

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

    default:
        print("an argument")
    }
}
Mark Adams
źródło
10
@AlbinStigo Process.arguments jest już tablicą ciągów, nie ma potrzeby tworzenia nowego.
Lance
9
Jak prawie zawsze najlepsza odpowiedź nie jest akceptowana. :)
HepaKKes
5
Jeśli kogokolwiek poza mną obchodzi, Proces jest w rzeczywistości wyliczeniem .
robobrobro
1
Jest Process.argumentstaki sam jak NSProcessInfo.processInfo().arguments?
Franklin Yu
5
W najnowszych migawkach Swift (migawka z dnia 28 lipca lub migawka z dnia 29 lipca) Processobiekt jest teraz znany jako CommandLineobiekt. Prawdopodobnie zostanie to w pełni włączone po oficjalnym wydaniu Swift 3.0.
TheSoundDefense
57

W Swift 3 użyj CommandLineenum zamiastProcess

Więc:

let arguments = CommandLine.arguments
Maciek Czarnik
źródło
46

Użyj stałych najwyższego poziomu C_ARGCi 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")
    }
}

Zauważ, że używam zakresu od, 1..C_ARGCponieważ pierwszym elementem C_ARGV„tablicy” jest ścieżka aplikacji.

C_ARGVZmiennej rzeczywistości nie jest tablicą, ale jest sub-skrypty jak tablicy.

orj
źródło
4
Możesz także użyć NSProcessInfo, tak jak robisz to w Objective-C.
Jack Lawrence
3
NSProcessInfo wymaga Foundation. Moja odpowiedź nie wymaga podkładu. Po prostu używa standardowej biblioteki Swift lang.
orj
7
C_ARCGwydaje się, że nie jest już obsługiwany.
juandesant
2
Mogę potwierdzić, że C_ARG nie działa już z najnowszą wersją narzędzi XCode w wersji 7.1 (7B91b).
svth
8
Zamiast tego możesz użyć Process.argci Process.argumentsdo tego, chociaż wygląda na to, że może się to zmienić na CommandLine.argci CommandLine.argumentswraz z ostatnimi zmianami języka.
TheSoundDefense
14

Każdy, kto chce używać starego „getopt” (dostępnego w Swift), może użyć tego jako odniesienia. Zrobiłem port Swift przykładu GNU w C, który można znaleźć pod adresem:

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

z pełnym opisem. Jest przetestowany iw pełni funkcjonalny. Nie wymaga też Fundacji.

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
źródło
0

Możesz utworzyć parser argumentów za pomocą CommandLine.arguments Array i dodać dowolną logikę.

Możesz to przetestować. Utwórz plikarguments.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)
}

skompiluj i uruchom:

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

Problem z budowaniem własnego parsera argumentów polega na uwzględnieniu wszystkich konwencji argumentów wiersza poleceń. Poleciłbym użycie istniejącego parsera argumentów.

Możesz użyć:

  • Moduł Vapor's Console
  • Parser argumentów TSCUtility używany przez menedżera Swift Package
  • Swift Argument Parser open-source firmy Apple

Pisałem o tym, jak budować narzędzia wiersza poleceń na wszystkich trzech. Powinieneś je sprawdzić i zdecydować, jaki styl najbardziej Ci odpowiada.

Jeśli jesteś zainteresowany, oto linki:

Derik Ramirez
źródło