Como você acessa os argumentos da linha de comando no Swift?

Respostas:

7

A Apple lançou a ArgumentParserbiblioteca para fazer exatamente isso:

Temos o prazer de anunciar ArgumentParser, uma nova biblioteca de código aberto que o torna simples - até mesmo agradável! - para analisar argumentos de linha de comando em Swift.

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


Swift Argument Parser

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

Comece declarando um tipo que define as informações que você precisa coletar da linha de comando. Decore cada propriedade armazenada com um dos ArgumentParserwrappers de propriedade de e declare conformidade com ParsableCommand.

A ArgumentParserbiblioteca analisa os argumentos da linha de comando, instancia seu tipo de comando e, em seguida, executa seu run()método personalizado ou sai com uma mensagem útil.

pkamb
fonte
305

Atualização 17/01/17: Atualizado o exemplo para Swift 3. Processfoi renomeado para CommandLine.


Atualização 30/09/2015: Atualizado o exemplo para funcionar no Swift 2.


Na verdade, é possível fazer isso sem Foundation ou C_ARGV e C_ARGC.

A biblioteca padrão do Swift contém uma estrutura CommandLineque possui uma coleção de Strings chamados arguments. Portanto, você pode ativar 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
fonte
10
@AlbinStigo Process.arguments já é um array de strings, não há necessidade de fazer um novo.
Lance
9
Como quase sempre, a melhor resposta não é a aceita. :)
HepaKKes
5
Se alguém além de mim se importa, Processo é na verdade uma enumeração .
robobrobro
1
É Process.argumentso mesmo que NSProcessInfo.processInfo().arguments?
Franklin Yu
5
Nos instantâneos Swift mais recentes (seja o instantâneo 7/28 ou o instantâneo 7/29), o Processobjeto agora é conhecido como o CommandLineobjeto. Isso provavelmente será totalmente incorporado quando o Swift 3.0 for oficialmente lançado.
TheSoundDefense
57

No Swift 3, use CommandLineenum em vez deProcess

Assim:

let arguments = CommandLine.arguments
Maciek Czarnik
fonte
46

Use as constantes de nível superior C_ARGCe 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")
    }
}

Observe que estou usando o intervalo de 1..C_ARGCporque o primeiro elemento da C_ARGV"matriz" é o caminho do aplicativo.

A C_ARGVvariável não é realmente uma matriz, mas pode ser submetida a scripts como uma matriz.

orj
fonte
4
Você também pode usar NSProcessInfo, assim como você faz em Objective-C.
Jack Lawrence
3
NSProcessInfo requer Foundation. Minha resposta não requer Fundação. Apenas usa a biblioteca padrão de idioma rápido.
orj
7
C_ARCGparece não ser mais compatível.
2015
2
Posso confirmar que C_ARG não funciona mais com a versão mais recente das ferramentas, XCode versão 7.1 (7B91b).
2015
8
Em vez disso, você pode usar Process.argce Process.argumentspara isso, embora pareça que isso possa estar mudando para CommandLine.argce CommandLine.argumentscom as alterações mais recentes do idioma.
TheSoundDefense
14

Quem quiser usar o antigo "getopt" (que está disponível no Swift) pode usá-lo como referência. Fiz um porte Swift do exemplo GNU em C que pode ser encontrado em:

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

com uma descrição completa. É testado e totalmente funcional. Também não requer Fundação.

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

Você pode criar um analisador de argumento usando o CommandLine.argumentsArray e adicionar qualquer lógica que desejar.

Você pode testar. Crie um arquivoarguments.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)
}

compile e execute:

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

O problema de você construir seu próprio analisador de argumento é levar em consideração todas as convenções de argumento da linha de comando. Eu recomendaria usar um Argument Parser existente.

Você pode usar:

  • Módulo Vapor's Console
  • TSCUtility Argument Parser usado pelo gerenciador de pacotes Swift
  • The Swift Argument Parser com código-fonte aberto da Apple

Eu escrevi sobre como construir ferramentas de linha de comando em todos os três. Você deve verificá-los e decidir qual estilo se adapta melhor a você.

Se você estiver interessado, aqui estão os links:

Derik Ramirez
fonte