Как получить доступ к аргументам командной строки в Swift?

Ответы:

7

Apple выпустила ArgumentParserбиблиотеку именно для этого:

Мы рады анонсировать ArgumentParserновую библиотеку с открытым исходным кодом, которая делает ее простой и даже приятной! - для анализа аргументов командной строки в Swift.

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


Быстрый синтаксический анализатор аргументов

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

Начните с объявления типа, который определяет информацию, которую необходимо собрать из командной строки. Украсьте каждое сохраненное свойство одной из ArgumentParserоболочек свойств и объявите соответствие ParsableCommand.

ArgumentParserБиблиотека разбирает аргументы командной строки, конкретизирует тип команды, а затем либо выполняет свой собственный run()метод или выход с полезным сообщением.

pkamb
источник
305

Обновление 17.01.17: Обновленный пример для Swift 3. Processбыл переименован в CommandLine.


Обновление 30.09.2015: обновлен пример для работы в Swift 2.


На самом деле это возможно сделать без Foundation или C_ARGV и C_ARGC.

Стандартная библиотека Swift содержит структуру, CommandLineкоторая имеет набор Stringимен arguments. Итак, вы можете включить такие аргументы:

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

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

    default:
        print("an argument")
    }
}
Марк Адамс
источник
10
@AlbinStigo Process.arguments уже представляет собой массив строк, создавать новую не нужно.
Lance
9
Практически всегда лучший ответ - не тот, который был принят. :)
HepaKKes
5
Если кому-то, кроме меня, интересно, Process на самом деле является перечислением .
robobrobro
1
Такое Process.argumentsже, как NSProcessInfo.processInfo().arguments?
Франклин Ю
5
В самых последних снимках Swift (снимок от 28 июля или 29 июля) Processобъект теперь известен как CommandLineобъект. Вероятно, это будет полностью включено после официального выпуска Swift 3.0.
TheSoundDefense
57

В Swift 3 используйте CommandLineenum вместоProcess

Так:

let arguments = CommandLine.arguments
Мацек Чарник
источник
46

Используйте константы верхнего уровня C_ARGCи 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")
    }
}

Обратите внимание, что я использую диапазон, 1..C_ARGCпотому что первый элемент C_ARGV«массива» - это путь к приложению.

C_ARGVПеременный фактически не является массив , но суб-скриптов как массив.

ORJ
источник
4
Вы также можете использовать NSProcessInfo, как и в Objective-C.
Джек Лоуренс
3
NSProcessInfo требует Foundation. Мой ответ не требует Foundation. Просто использует стандартную библиотеку swift lang.
orj 04
7
C_ARCGпохоже, больше не поддерживается.
juandesant
2
Я могу подтвердить, что C_ARG больше не работает с последней версией инструментов XCode Version 7.1 (7B91b).
11
8
Вместо этого вы можете использовать Process.argcи Process.argumentsдля этого, хотя похоже, что это может быть изменено на CommandLine.argcи CommandLine.argumentsс самыми последними изменениями языка.
TheSoundDefense 08
14

Любой, кто хочет использовать старый "getopt" (который доступен в Swift), может использовать его как ссылку. Я сделал Swift-порт примера GNU на C, который можно найти по адресу:

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

с полным описанием. Он протестирован и полностью работоспособен. Также не требуется 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)])!)'")
}
Мишель Далл'Агата
источник
0

Вы можете создать парсер аргументов, используя CommandLine.argumentsмассив и добавить любую логику, которая вам нравится.

Вы можете это проверить. Создать файлarguments.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)
}

скомпилируйте и запустите:

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

Проблема с созданием собственного анализатора аргументов заключается в учете всех соглашений об аргументах командной строки. Я бы рекомендовал использовать существующий парсер аргументов.

Вы можете использовать:

  • Модуль консоли Vapor
  • Парсер аргументов TSCUtility, используемый менеджером пакетов Swift
  • Swift Argument Parser с открытым исходным кодом от Apple

Я писал о том, как создавать инструменты командной строки для всех трех. Вы должны проверить их и решить, какой стиль вам больше подходит.

Если вам интересно, вот ссылки:

Дерик Рамирес
источник