¿Cómo se accede a los argumentos de la línea de comandos en Swift?

Respuestas:

7

Apple ha lanzado la ArgumentParserbiblioteca para hacer precisamente esto:

Estamos encantados de anunciar ArgumentParseruna nueva biblioteca de código abierto que lo hace sencillo, ¡incluso agradable! - para analizar los argumentos de la línea de comandos en Swift.

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


Analizador de argumentos veloz

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

Comience declarando un tipo que defina la información que necesita recopilar desde la línea de comando. Decore cada propiedad almacenada con uno de ArgumentParserlos envoltorios de propiedad y declare la conformidad con ParsableCommand.

La ArgumentParserbiblioteca analiza los argumentos de la línea de comandos, crea una instancia de su tipo de comando y luego ejecuta su run()método personalizado o sale con un mensaje útil.

pkamb
fuente
305

Actualización 17/01/17: Se actualizó el ejemplo de Swift 3. Processha cambiado de nombre CommandLine.


Actualización 30/09/2015: Se actualizó el ejemplo para que funcione en Swift 2.


De hecho, es posible hacer esto sin Foundation o C_ARGV y C_ARGC.

La biblioteca estándar de Swift contiene una estructura CommandLineque tiene una colección de Strings llamados arguments. Entonces podrías activar argumentos como este:

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

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

    default:
        print("an argument")
    }
}
Mark Adams
fuente
10
@AlbinStigo Process.arguments ya es una matriz de cadenas, no es necesario crear una nueva.
Lance
9
Como casi siempre, la mejor respuesta no es la aceptada. :)
HepaKKes
5
Si alguien además de mí se preocupa, Process es en realidad una enumeración .
robobrobro
1
¿Es Process.argumentslo mismo que NSProcessInfo.processInfo().arguments?
Franklin Yu
5
En las instantáneas de Swift más recientes (ya sea la instantánea del 28/7 o la instantánea del 29/7), el Processobjeto ahora se conoce como el CommandLineobjeto. Esto probablemente se incorporará por completo una vez que Swift 3.0 se lance oficialmente.
TheSoundDefense
57

En Swift 3 use CommandLineenum en lugar deProcess

Entonces:

let arguments = CommandLine.arguments
Maciek Czarnik
fuente
46

Utilice las constantes de nivel superior C_ARGCy 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")
    }
}

Tenga en cuenta que estoy usando el rango de 1..C_ARGCporque el primer elemento de la C_ARGV"matriz" es la ruta de la aplicación.

La C_ARGVvariable no es en realidad una matriz, sino que es sub-programable como una matriz.

orj
fuente
4
También puede usar NSProcessInfo, tal como lo hace en Objective-C.
Jack Lawrence
3
NSProcessInfo requiere Foundation. Mi respuesta no requiere Fundación. Solo usa la lib estándar swift lang.
orj
7
C_ARCGparece que ya no se admite.
juandesant
2
Puedo confirmar que C_ARG ya no funciona con la última versión de las herramientas, XCode Versión 7.1 (7B91b).
2015
8
En su lugar se puede utilizar Process.argcy Process.argumentspara esto, aunque parece que esto podría estar cambiando para CommandLine.argcy CommandLine.argumentscon los cambios más recientes a la lengua.
TheSoundDefense
14

Cualquiera que quiera usar el antiguo "getopt" (que está disponible en Swift) puede usarlo como referencia. Hice un puerto Swift del ejemplo de GNU en C que se puede encontrar en:

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

con una descripción completa. Está probado y es completamente funcional. Tampoco requiere Fundación.

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
fuente
0

Puede crear un analizador de argumentos utilizando CommandLine.argumentsArray y agregar la lógica que desee.

Puedes probarlo. Crea un archivoarguments.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)
}

compílelo y ejecútelo:

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

El problema con la construcción de su propio analizador de argumentos es tener en cuenta todas las convenciones de argumentos de la línea de comandos. Recomendaría usar un analizador de argumentos existente.

Podrías usar:

  • Módulo de consola de Vapor
  • Analizador de argumentos de TSCUtility utilizado por el administrador de paquetes Swift
  • El analizador de argumentos Swift de código abierto de Apple

He escrito sobre cómo construir herramientas de línea de comandos en los tres. Deberías echarles un vistazo y decidir qué estilo te queda mejor.

Si está interesado aquí están los enlaces:

Derik Ramírez
fuente