don't stop believing

[swift] command line tool - static/interactive 본문

Swift/Basic

[swift] command line tool - static/interactive

Tongchun 2017. 8. 17. 18:03

Command Line Tool을 좀더 있어보이게 만들어 봅시다.

프로그램명 뒤에 옵션을 붙여서 실행시키는 static 모드와 대화형의 interactive 모드를 만들어 봅시다.


사용할 옵션은 -n, -p, -h 그리고 -q로 하겠습니다.

-n: 이름을 등록하도록 합니다.

-p: 전화번호를 등록하도록 합니다.

-h: 사용 설명이 나오도록 합니다.

-q: 인터렉션 모드에서 종료하도록 합니다.


[swift command line tool 만들기 기본편]에서 이어서 진행하겠습니다.


xCode에서 main.swift가 있는 경로에 swift 파일을 추가합니다. 이름은 ConsoleIO.swift로 하겠습니다.

Class도 파일명과 동일하게 만들고 console에서의 input과 output을 담당하도록 합니다.

import Foundation

class ConsoleIO {
}

Output에 대한 타입을 지정합니다.

아래 enum 을 import와 class 사이에 작성합니다.

enum OutputType {
    case standard
    case error
}

콘솔에 메시지를 쓰는 함수를 작성합니다. 함수는 ConsoleIO 클래스 안에 위치합니다.

func writeMessage(_ message: String, to: OutputType = .standard) {
    switch to {
    case .standard:
        print("\(message)")
    case .error:
        fputs("Error: \(message)\n", stderr)
    }
}

프로그램의 기본 사용법을 확인하는 함수를 만듭니다.

writeMessage() 함수를 이용하고 아래 코드를 ConsoleIO 클래스 안에 작성합니다.

func printUsage() {
    let executableName = (CommandLine.arguments[0] as NSString).lastPathComponent

    writeMessage("usage:")
    writeMessage("\(executableName) -n string1 string2")
    writeMessage("or")
    writeMessage("\(executableName) -p string")
    writeMessage("or")
    writeMessage("\(executableName) -h to show usage information")
    writeMessage("Type \(executableName) without an option to enter interactive mode.")
}

CommandLine.arguments는 Input String을 빈칸(띄어쓰기)을 구분자로 각 String을 받아옵니다.

CommandLine.arguments[0]은 프로그램 이름이며 1부터 옵션 등을 받아오게 됩니다.


이제 프로그램 로직 처리를 담당할 class를 만들어 보겠습니다.

먼저 파일을 추가 합니다. Execute.swift 라고 파일을 만들고 아래 class를 추가 합니다.

import Foundation

class Execute {
}

프로그램이 사용할 옵션을 정의합니다.

enum 을 import와 class 사이에 작성합니다.

enum OptionType: String {
    case name = "n"
    case phone = "p"
    case help = "h"
    case quit = "q"
    case unknown

    init(value: String) {
        switch value {
        case "n": self = .name
        case "p": self = .phone
        case "h": self = .help
        case "q": self = .quit
        default: self = .unknown
        }
    }
}

Execute 클래스 안에 OptionType을 확인하는 함수를 만들어 줍니다.

함수명은 getOption()으로 하고 Execute 클래스 안에 위치합니다.

func getOption(_ option: String) -> (option: OptionType, value: String) {
    return (OptionType(value: option), option)
}

이제 staticMode를 만들어 봅니다.

Input argument 1 부터 받아서 옵션을 확인하고 해당하는 액션을 수행합니다.

func staticMode() {
    let argCount = CommandLine.argc
    let argOption = CommandLine.arguments[1]
    let argValue = CommandLine.arguments[2]
    let (option, value) = getOption(argOption.substring(from: argOption.index(argOption.startIndex, offsetBy: 1)))

    switch option {
    case .name:
        consoleIO.writeMessage("Argument count: \(argCount) Option: \(option)'(\(value))' value: \(argValue)")

    case .phone:
        consoleIO.writeMessage("Argument count: \(argCount) Option: \(option)'(\(value))' value: \(argValue)")

    case .help:
        consoleIO.printUsage()

    default:
        consoleIO.printUsage()
    }
}

이제 main.swlft 파일을 수정하고 static 모드로 실행해 봅시다.

먼저 main.swift 파일을 아래처럼 수정합니다.

import Foundation

if CommandLine.argc < 3 {
    print("no argument.")
} else {
    execute.staticMode()
}

빌드는 xCode 실행 후 command + B를 누르면 됩니다. 그리고 실행은 command + R 또든 상단 메뉴의 실행 버튼을 클릭합니다.

실행을 하면 xCode 하단 console 창에 no argument. 라고 나옵니다. 당연히 인자값이 없기 때문이죠.

인자값을 넣기 위해 Terminal에서 빌드하고 실행해 보겠습니다.


Mac의 Terminal을 실행 시키고 프로젝트가 있는 위치로 이동합니다.

저는 아래와 같은 경로에 있네요.

$ cd Document/JakeWork/nGle001

빌드를 합니다.

$ swift build

그리고 debug 모드 실행파일을 실행합니다. 인자값을 줘야겠죠.

$ .build/debug/nGle001 -n dejavu
Argument count: 3 Option: name'(n)' value: dejavu

xCode에서도 인자값을 넣어서 실행할 수 있습니다.

xCode 상단 실행버튼 옆 active scheme 창에서 Edit scheme을 선택합니다.

Run 의 Arguments 탭에서 Arguments Passed On Launch 항목에 인자값을 추가합니다. 저는 -n tongchun 이라고 넣고 닫아 줍니다.

그리고 다시 xCode의 실행 버튼을 클릭하면 아래 Console창에 인자값이 적용된 Output 텍스트가 보입니다.

이제 interactive 모드를 만들어 봅시다.

Execute.swift 파일의 Execute 클래스 안에 interactiveMode() 함수를 만들어 줍니다.

while 문을 사용해 프로그램이 종료되지 않도록 합니다. 그리고 option을 확인해 해당하는 출력을 하게 됩니다.

func interactiveMode() {
    consoleIO.writeMessage("Welcome to nGle.")
    var shouldQuit = false

    while !shouldQuit {

        consoleIO.writeMessage("Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit.")
        let (option, value) = getOption(consoleIO.getInput())

        switch option {
        case .name:
            consoleIO.writeMessage("What's your name?")
            let first = consoleIO.getInput()

            consoleIO.writeMessage("What do you do?")
            let second = consoleIO.getInput()

            consoleIO.writeMessage("\(first) is smart guy. \(second)")

        case .phone:
            consoleIO.writeMessage("What's your phone number?")
            let first = consoleIO.getInput()

            consoleIO.writeMessage("\(first) is your phone number.")

        case .help:
            consoleIO.printUsage()

        case .quit:
            shouldQuit = true

        default:
            consoleIO.writeMessage("Unknown option \(value)", to: .error)
            consoleIO.printUsage()
        }
    }
}

그 다음 main.swift 파일에서 인자값이 있으면 staticMode() 없다면 interactiveMode()를 호출하게 수정합니다.

let execute = Execute()

if CommandLine.argc < 3 {
    execute.interactiveMode()
} else {
    execute.staticMode()
}

xCode에서 실행버튼 또는 Command + B, Command + R을 하면 빌드와 실행이 되고 아래 console창에 staticMode의 결과가 보이게 됩니다.

Edit scheme의 Run에서 Arguments Passed On Launch 값을 - 버튼을 눌러 제거하고 다시 실행하면 interactiveMode로 실행되게 됩니다.

xCode의 console 창에 n을 넣고 엔터를 치면 "What's your name?" 이라고 나오는게 보입니다.

q를 누르면 interactiveMode가 종료됩니다.


Terminal에서도 다시 빌드하고 실행하면 staticMode와 interactiveMode를 확인할 수 있습니다.

만약 xCode에서 빌드 후 console창에서 실행하는 것이 아니라 Ternimal로 바로 확인하고 싶다면 Scheme을 추가하면 됩니다.


New Scheme...을 클릭해 새로운 Scheme을 등록합니다.

Target을 nGle001, Name은 nGle001 on Terminal로 변경하고 OK를 클릭 합니다.

다시 생성된 nGle001 on Terminal을 선택 후 Edit Scheme을 클릭합니다.

Run의 Info 탭에서 Executable을 Terminal로 선택해 줍니다. Terminal은 other 선택 후 find 창에서 Applications/Utilities/Terminal을 선택하면 됩니다.

그리고 Debug executable은 체크를 해제합니다.

마지막으로 Arguments 탭에서 Arguments Passed On Launch에 아래와 같이 등록합니다.

${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}

Close 클릭해 Edit Scheme창을 닫고 xCode의 실행 버튼을 클릭하면 Terminal이 실행되는 것을 확인할 수 있습니다.






'Swift > Basic' 카테고리의 다른 글

탈출 클로저 @escaping  (0) 2018.01.31
defer (후처리)  (0) 2018.01.24
Swift Access Control  (0) 2018.01.19
SPM에서 framework와 실행부분 코드 분리하기  (0) 2017.09.15
[swift] command line tool 만들기 기본편  (0) 2017.08.16
Comments