How do you access command line arguments in Swift?

MacosCommand Line-ArgumentsSwift

Macos Problem Overview


How do you access command line arguments for a command line application in Swift?

Macos Solutions


Solution 1 - Macos

Update 01/17/17: Updated the example for Swift 3. Process has been renamed to CommandLine.


Update 09/30/2015: Updated the example to work in Swift 2.


It's actually possible to do this without Foundation or C_ARGV and C_ARGC.

The Swift standard library contains a struct CommandLine which has a collection of Strings called arguments. So you could switch on arguments like this:

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

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

    default:
        print("an argument")
    }
}

Solution 2 - Macos

In Swift 3 use CommandLine enum instead of Process

So:

let arguments = CommandLine.arguments

Solution 3 - Macos

Use the top level constants C_ARGC and 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")
    }
}

Note that I'm using the range of 1..C_ARGC because the first element of the C_ARGV "array" is the application's path.

The C_ARGV variable is not actually an array but is sub-scriptable like an array.

Solution 4 - Macos

Anyone who wants to use the old "getopt" (which is available in Swift) can use this as reference. I made a Swift port of the GNU example in C one can find at:

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

with a full description. It's tested and fully functional. It doesn't require Foundation either.

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)])!)'")
}

Solution 5 - Macos

Apple has released the ArgumentParser library for doing just this:

> We’re delighted to announce ArgumentParser, a new open-source library that makes it straightforward — even enjoyable! — to parse command-line arguments in Swift. > > https://swift.org/blog/argument-parser/


Swift Argument Parser

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

> Begin by declaring a type that defines the information you need to collect from the command line. Decorate each stored property with one of ArgumentParser's property wrappers, and declare conformance to ParsableCommand. > > The ArgumentParser library parses the command-line arguments, instantiates your command type, and then either executes your custom run() method or exits with useful a message.

Solution 6 - Macos

You could create an argument parser by using the CommandLine.arguments Array and add any logic you like.

You can test it. Create a file 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)
}

compile it and run it:

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

The issue with you building your own argument parser is taking into account all the command-line argument conventions. I would recommend using an existing Argument Parser.

You could use:

  • Vapor's Console module
  • TSCUtility Argument Parser used by the Swift Package manager
  • The Swift Argument Parser open-sourced by Apple

I've written about how to build command-line tools on all three. You should check them out and decide what style suits you best.

If you are interested here are the links:

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnthony MittazView Question on Stackoverflow
Solution 1 - MacosMark AdamsView Answer on Stackoverflow
Solution 2 - MacosMaciek CzarnikView Answer on Stackoverflow
Solution 3 - MacosorjView Answer on Stackoverflow
Solution 4 - MacosMichele Dall'AgataView Answer on Stackoverflow
Solution 5 - MacospkambView Answer on Stackoverflow
Solution 6 - MacosDerik RamirezView Answer on Stackoverflow