kodeco.com Forums

Command Line Programs on OS X Tutorial

Discover how easy it is to get started making your own terminal-based apps with this command line programs on OS X tutorial.

This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1147-command-line-programs-on-macos-tutorial

I am enjoying the tutorial, but running the application from the command line is not working for me at all. When I navigate to the app in the terminal and type Panagram I get -bash: Panagram: command not found and when I follow the instructions in “Launching Outside Xcode” I get the following result in the terminal window:

Last login: Thu May 19 11:30:40 on ttys006
~$ /Users/natebirkholz/Library/Developer/Xcode/DerivedData/Panagram-fxptyxcxkrwrvqbtjhtvedhpsqcw/Build/Products/Debug/Panagram ; exit;
Saving session...
...copying shared history...
...saving history...truncating history files...

[Process completed]

Clearly I have some environment variables set up improperly but am at a loss, anyone got a suggestion?

Note that when I download the finished version from the site it runs properly, but I am having trouble finding the guilty setting.

Hi, i’m glad that you enjoy the tutorial so far. For now i’m sure nothing is messed up with your environment variables, i can reproduce your problem and maybe it has something to do with the latest OS X update or we missed something in our QA, but i’m sure it’s Apples fault :wink:. Which OS X and Xcode version do you use?

OSX 10.11.4 and Xcode 7.3. I was forgetting to run the app from the cmmcd line by prepending ./ so I run it by typing ./Panagram and it just silently fails. But if I run it from your build it succeeds. Not sure what the issue is.

Found it. I am really dumb. I was running it without parameters and thus it was hitting the first line which at that point in the tutorial was just a comment. Silly me.

The idea to use the terminal launch the app doesn’t work if you already have the terminal app open: it will get the focus and sit there not doing much.

I don’t have that issue at all, I just get a new window opening if the terminal is already running. I can’t see an obvious setting that is preventing it from opening for you though.

Great tutorial

Is there anywhere I can see how to create a GUI(eg in an OSX app) for a Command line programs to look at and will parse the output?

You should have a look at our NSTask tutorial.

Interesting Pierre- do you have a link?

Hmm, seems like the link feature doesn’t work properly. I had it linked in my first reply but it brings you only to the top of this discussion. Next try: https://www.raywenderlich.com/125071/nstask-tutorial-os-x

Edit: My fault, the link was wrong.

Hi there,

I’m just wondering why this tutorial uses NSFileHandle.fileHandleWithStandardInput() rather than readLine(), part of the Swift standard library. Is there a specific advantage to using this?

One of the most frustrating things I’ve noticed about Swift is the lack of simple ways to retrieve data from stdin, as with Java’s Scanner class, or Python’s input() function.

Hi there, is no special advantage with NSFileHandle, it is just another way to get input from stdin.

That’s great, thank you!
One last question - am I right in thinking, then, in order to retrieve anything other than a String? from either NSFileHandle or readLine(), I need to write the functions to check and convert the input from stdin myself?

Thank you for that great tutorial! It’s excactly what i was looking for. While i’m a ‘swift-newbie’ it took some time, but now it worked well and most important, i think i understood the code (most of it :smile: ).
But there are 2 things i’d like to know:

  1. There is only the “-p” argument passed to the programm. Why is it accepting “-a” and “-h” ass well?

  2. How can i use more than one argument, like "palindrome -p level -a silent listen?

Great you liked the tutorial. To your questions.

  1. Command line arguments are just strings passed to the program and it is up to you to do something useful with it. If you don’t want to accept other arguments than the ones you defined e.g. -p you have to throw an error yourself.
    The example program can handle the a,p and h option and everything else is ignored.

  2. It’s the same like 1. if you want to use more arguments you must parse them and handle it the way you want. This is done in the tutorial for the a and p option. In your example you have to iterate through the passed arguments, check what the first is “p” then check the next arguments until you hit the next option “a”. The strings between -p and -a belong to the -p option and you must store them for later use.

There are also some libraries out there to help you with this task like GitHub - jatoben/CommandLine: A pure Swift library for creating command-line interfaces.

Thanks for the tutorial!

I successfully went through with Swift 3. Most of the Swift 3 changes are handled by Xcode 8’s auto-correction or can be found here.

However, I struggled quite a bit with //3 of the staticMode() function in Panagram.swift. So, in case anybody else has problems here too, this is what finally worked with Swift 3:

let (option, value) = consoleIO.getOption(option: argument.substring(from: argument.index(argument.startIndex, offsetBy: 1)))

Not sure if it’s the best solution, but… it works :slight_smile:


Hi Jean-Pierre, thank you very much for your explanation. Theoreticly i understood what you said. But as i tried to adapt the code, i struggled parsing of the arguments.
i added:

let argument2 = Process.arguments[2]
let (option2, value) = consoleIO.getOption(argument2.substringFromIndex(argument2.startIndex.advancedBy(1)))

The second line gets the error “Definition conflicts with previous value”. So it seems i didn’t get it. :persevere:
Anybody could help me to understand what to do please. Thanks. :slight_smile: