Vincent Gable’s Blog

March 5, 2008

Calling the Command Line from Cocoa

Filed under: Cocoa,MacOSX,Objective-C,Programming,Tips,UNIX | , , , ,
― Vincent Gable on March 5, 2008

The best way to call a shell-command from Coca is by using an NSTask. Here are the three resources on using an NSTask that I found the most helpful:
CocoDev’s write up
A few quick exaples
NSTask Class Refrence

And here is some sample code to do it for you. You are free to use this code however you please, but attribution is always appreciated. The two principle functions are:

+ (NSString*) executeShellCommandSynchronously:(NSString*)command executes the command “command” with sh, wait until it finishes, and return whatever it printed to stdout and stderr as an NSString.
CAUTION: may deadlock under some circumstances if the output gets so big it fills the pipe. See http://dev.notoptimal.net/search/label/NSTask for an overview of the problem, and a solution. I have not experienced the problem myself, so I can’t comment.

executeShellCommandAsynchronously: will have sh execute command in the background, without blocking anything.

For quick hacks, the POSIX int system(const char* command) function, might be a good one-line solution. It synchronously evaluates command with sh.

Enjoy!

EDITED 2009-11-29: this code probably won’t have the same $PATH you would get if you used Terminal. See this question on stackoverflow for more details. A solution that seems to work is to do,

    [task setLaunchPath:@"/bin/bash"];
    NSArray	*args = [NSArray arrayWithObjects:@"-l",
    				 @"-c",
    				 commandlineHere,
    				 nil];
    [task setArguments: args];

This launches bash (not in sh compatibility mode), and -l (lowercase L) tells it to “act as if it had been invoked as a login shell”. I haven’t tested this on systems where bash isn’t the default shell. There are lots of ways $PATH could be set, and I haven’t tested them all. But you are almost certainly going to be OK if everything you refer to is in /usr/bin:/bin:/usr/sbin:/sbin.

6 Comments »

  1. [...] you can’t tell yourself to start up when you aren’t running. Here is one solution, use NSTask to run a very short script that you can embed right in your Objective-C code: kill -9 YourPID open [...]

    Pingback by Vincent Gable » Restarting Your Cocoa Application — October 5, 2008 @ 7:35 pm

  2. Thanks! Your ShellTask class was just what I needed.

    Comment by Jack Repenning — November 13, 2008 @ 6:45 am

  3. Thanks. This is great! Is there a way to execute several commands within the same Terminal session? I’m calling executeShellCommandSynchronously multiple times to traverse folders and and retreive contents of a file:

    cd /
    cd Users/theuser/Thefolder
    vi somefile.txt

    The problem is that each command executes in its own Terminal session. So the second command gives a folder not found because I’m still in the build/debug folder. Any suggestions? Thanks.

    Comment by Xcode newbie — January 19, 2009 @ 9:47 am

  4. What I would suggest doing is putting those dependent shell commands together in their own shell script, and then executing the shell script.
    Once you have added the script, MyScript.sh, to your Xcode project, you can have the shell run it like:

    NSString *pathToMyScript = [[NSBundle mainBundle] pathForResource:@”MyScript” ofType:@”sh”];
    [[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObject:pathToMyScript]] waitUntilExit];

    Comment by Vincent Gable — January 19, 2009 @ 7:33 pm

  5. Thanks. This is getting off topic but I’d like to run some sqlite commands. After executing folder change commands in the .sh file, these commands execute:

    sqlite3 myDB.sqlite
    .import dbArea.txt Area

    When I run the .sh file from Terminal, I’m at an sqlite prompt. The import command doesn’t execute. Any ideas what’s going on?

    Comment by Xcode newbie — January 20, 2009 @ 10:11 am

  6. Used to get the primary mac address of the computer in order to run an mathematical permutation to get a unique “computer code”

    Comment by Alex Akers — February 15, 2009 @ 1:29 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress