Comment accéder aux arguments de ligne de commande dans Swift?

Réponses:

7

Apple a publié la ArgumentParserbibliothèque pour faire exactement cela:

Nous sommes ravis d'annoncer ArgumentParser, une nouvelle bibliothèque open-source qui la rend simple - même agréable! - pour analyser les arguments de ligne de commande dans Swift.

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


Analyseur d'argument rapide

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

Commencez par déclarer un type qui définit les informations que vous devez collecter à partir de la ligne de commande. Décorez chaque propriété stockée avec l'un des ArgumentParserwrappers de propriété de et déclarez la conformité à ParsableCommand.

La ArgumentParserbibliothèque analyse les arguments de ligne de commande, instancie votre type de commande, puis exécute votre run()méthode personnalisée ou quitte avec un message utile.

pkamb
la source
305

Mise à jour 17/01/17: mise à jour de l'exemple pour Swift 3. Processa été renommé en CommandLine.


Mise à jour 30/09/2015: mise à jour de l'exemple pour qu'il fonctionne dans Swift 2.


Il est en fait possible de faire cela sans Foundation ou C_ARGV et C_ARGC.

La bibliothèque standard Swift contient une structure CommandLinequi a une collection de Strings appelée arguments. Vous pouvez donc activer des arguments comme celui-ci:

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

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

    default:
        print("an argument")
    }
}
Mark Adams
la source
10
@AlbinStigo Process.arguments est déjà un tableau de chaînes, pas besoin d'en créer une nouvelle.
Lance
9
Comme presque toujours, la meilleure réponse n'est pas celle acceptée. :)
HepaKKes
5
Si quelqu'un d'autre que moi s'en soucie, Process est en fait une énumération .
robobrobro
1
Est-ce Process.argumentsle même que NSProcessInfo.processInfo().arguments?
Franklin Yu
5
Dans les instantanés Swift les plus récents (soit l'instantané 7/28, soit l'instantané 7/29), l' Processobjet est maintenant connu sous le nom d' CommandLineobjet. Cela sera probablement entièrement intégré une fois que Swift 3.0 sera officiellement publié.
TheSoundDefense
57

Dans Swift 3, utilisez CommandLineenum au lieu deProcess

Alors:

let arguments = CommandLine.arguments
Maciek Czarnik
la source
46

Utilisez les constantes de niveau supérieur C_ARGCet 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")
    }
}

Notez que j'utilise la plage de 1..C_ARGCcar le premier élément du C_ARGV"tableau" est le chemin de l'application.

La C_ARGVvariable n'est pas réellement un tableau mais est sous-scriptable comme un tableau.

orj
la source
4
Vous pouvez également utiliser NSProcessInfo, comme vous le faites dans Objective-C.
Jack Lawrence
3
NSProcessInfo nécessite Foundation. Ma réponse n'exige pas la Fondation. Utilise juste la lib standard swift lang.
orj
7
C_ARCGsemble ne plus être pris en charge.
juandesant le
2
Je peux confirmer que C_ARG ne fonctionne plus avec la dernière version des outils, XCode Version 7.1 (7B91b).
svth
8
Vous pouvez à la place utiliser Process.argcet Process.argumentspour cela, bien qu'il semble que cela puisse changer pour CommandLine.argcet CommandLine.argumentsavec les modifications les plus récentes de la langue.
TheSoundDefense
14

Quiconque souhaite utiliser l'ancien "getopt" (qui est disponible dans Swift) peut l'utiliser comme référence. J'ai fait un portage Swift de l'exemple GNU en C que l'on peut trouver sur:

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

avec une description complète. Il est testé et entièrement fonctionnel. Cela ne nécessite pas non plus de Fondation.

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
la source
0

Vous pouvez créer un analyseur d'arguments à l'aide du CommandLine.argumentstableau et ajouter la logique de votre choix.

Vous pouvez le tester. Créer un fichierarguments.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)
}

compilez-le et exécutez-le:

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

Le problème avec la construction de votre propre analyseur d'arguments est de prendre en compte toutes les conventions d'argument de ligne de commande. Je recommanderais d'utiliser un analyseur d'arguments existant.

Vous pouvez utiliser:

  • Module de console de Vapor
  • Analyseur d'arguments TSCUtility utilisé par le gestionnaire de paquets Swift
  • Le Swift Argument Parser open-source par Apple

J'ai écrit sur la façon de créer des outils de ligne de commande sur les trois. Vous devriez les vérifier et décider quel style vous convient le mieux.

Si vous êtes intéressé, voici les liens:

Derik Ramirez
la source