Command Line Programs on macOS Tutorial
Discover how easy it is to make your own terminal-based apps with this command line programs on macOS tutorial. Updated for Xcode 9 and Swift 4! By Eric Soto.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Handle Input Interactively
Now that you have a basic version of Panagram working, you can make it even more useful by adding the ability to type in the arguments interactively via the input stream.
In this section, you will add code so when Panagram is started without arguments, it will open in interactive mode and prompt the user for the input it needs.
First, you need a way to get input from the keyboard. stdin
is attached to the keyboard and is therefore a way for you to collect input from users interactively.
Open ConsoleIO.swift and add the following method to the class:
func getInput() -> String {
// 1
let keyboard = FileHandle.standardInput
// 2
let inputData = keyboard.availableData
// 3
let strData = String(data: inputData, encoding: String.Encoding.utf8)!
// 4
return strData.trimmingCharacters(in: CharacterSet.newlines)
}
Taking each numbered section in turn:
- First, grab a handle to
stdin
. - Next, read any data on the stream.
- Convert the data to a string.
- Finally, remove any newline characters and return the string.
Next, open Panagram.swift and add the following method to the class:
func interactiveMode() {
//1
consoleIO.writeMessage("Welcome to Panagram. This program checks if an input string is an anagram or palindrome.")
//2
var shouldQuit = false
while !shouldQuit {
//3
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 .anagram:
//4
consoleIO.writeMessage("Type the first string:")
let first = consoleIO.getInput()
consoleIO.writeMessage("Type the second string:")
let second = consoleIO.getInput()
//5
if first.isAnagramOf(second) {
consoleIO.writeMessage("\(second) is an anagram of \(first)")
} else {
consoleIO.writeMessage("\(second) is not an anagram of \(first)")
}
case .palindrome:
consoleIO.writeMessage("Type a word or sentence:")
let s = consoleIO.getInput()
let isPalindrome = s.isPalindrome()
consoleIO.writeMessage("\(s) is \(isPalindrome ? "" : "not ")a palindrome")
default:
//6
consoleIO.writeMessage("Unknown option \(value)", to: .error)
}
}
}
Taking a look at what's going on above:
- First, print a welcome message.
-
shouldQuit
breaks the infinite loop that is started in the next line. - Prompt the user for input and convert it to one of the two options, if possible.
- If the option was for anagrams, prompt the user for the two strings to compare.
- Write the result out. The same logic flow applies to the palindrome option.
- If the user enters an unknown option, print an error and start the loop again.
At the moment, you have no way to interrupt the while
loop. In Panagram.swift add the following line to the OptionType
enum:
case quit = "q"
Next, add the following line to the enum's init(_:)
:
case "q": self = .quit
In the same file, add a .quit
case to the switch
statement inside interactiveMode()
:
case .quit:
shouldQuit = true
Then, change the .unknown
case definition inside staticMode()
as follows:
case .unknown, .quit:
Open main.swift and replace the comment //TODO: Handle interactive mode
with the following:
panagram.interactiveMode()
To test interactive mode, you must not have any arguments defined in the Scheme.
So, remove the two arguments you defined earlier. Select Edit Scheme... from the toolbar menu. Select each argument and then click the - sign under Arguments Passed On Launch. Once all arguments are deleted, click Close:
Build and run, and you'll see the following output in the Console:
Welcome to Panagram. This program checks if an input string is an anagram or palindrome. Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit.
Try out the different options. Type an option letter (do not prefix with a hyphen) followed by Return. You will be prompted for the arguments. Enter each value followed by Return. In the Console you should see something similar to this:
a Type the first string: silent Type the second string: listen listen is an anagram of silent Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit. p Type a word or sentence: level level is a palindrome Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit. f Error: Unknown option f Type 'a' to check for anagrams or 'p' for palindromes type 'q' to quit. q Program ended with exit code: 0
Launching Outside Xcode
Normally, a command-line program is launched from a shell utility like Terminal (vs. launching it from an IDE like Xcode). The following section walks you through launching your app in Terminal.
There are different ways to launch your program via Terminal. You could find the compiled binary using the Finder and start it directly via Terminal. Or, you could be lazy and tell Xcode to do this for you. First, you'll learn the lazy way.
Launch your app in Terminal from Xcode
Create a new scheme that will open Terminal and launch Panagram in the Terminal window. Click on the scheme named Panagram in the toolbar and select New Scheme:
Name the new scheme Panagram on Terminal:
Ensure the Panagram on Terminal scheme is selected as the active scheme. Click the scheme and select Edit Scheme... in the popover.
Ensure that the Info tab is selected and then click on the Executable drop down and select Other. Now, find the Terminal.app in your Applications/Utilities folder and click Choose. Now that Terminal is your executable, uncheck Debug executable.
Your Panagram on Terminal scheme's Info tab should look like this:
Next, select the Arguments tab, then add one new argument:
${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}
Finally, click Close.
Now, make sure you have the scheme Panagram on Terminal selected, then build and run your project. Xcode will open Terminal and pass through the path to your program. Terminal will then launch your program as you'd expect.
Launch your app directly from Terminal
Open Terminal from your Applications/Utilities folder.
In the Project Navigator select your product under the Products group. Copy your debug folder's Full Path from Xcode's Utility area as shown below (do not include "Panagram"):
Open a Finder window and select the Go/Go to Folder... menu item and paste the full path you copied in the previous step into the dialog's text field:
Click Go and Finder navigates to the folder containing the Panagram executable:
Drag the Panagram executable from Finder to the Terminal window and drop it there. Switch to the Terminal window and hit Return on the keyboard. Terminal launches Panagram in interactive mode since no arguments were specified: