Execute a terminal command from a Cocoa app Execute a terminal command from a Cocoa app objective-c objective-c

Execute a terminal command from a Cocoa app


You can use NSTask. Here's an example that would run '/usr/bin/grep foo bar.txt'.

int pid = [[NSProcessInfo processInfo] processIdentifier];NSPipe *pipe = [NSPipe pipe];NSFileHandle *file = pipe.fileHandleForReading;NSTask *task = [[NSTask alloc] init];task.launchPath = @"/usr/bin/grep";task.arguments = @[@"foo", @"bar.txt"];task.standardOutput = pipe;[task launch];NSData *data = [file readDataToEndOfFile];[file closeFile];NSString *grepOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];NSLog (@"grep returned:\n%@", grepOutput);

NSPipe and NSFileHandle are used to redirect the standard output of the task.

For more detailed information on interacting with the operating system from within your Objective-C application, you can see this document on Apple's Development Center: Interacting with the Operating System.

Edit: Included fix for NSLog problem

If you are using NSTask to run a command-line utility via bash, then you need to include this magic line to keep NSLog working:

//The magic line that keeps your log where it belongstask.standardOutput = pipe;

An explanation is here: https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask


kent's article gave me a new idea. this runCommand method doesn't need a script file, just runs a command by a line:

- (NSString *)runCommand:(NSString *)commandToRun{    NSTask *task = [[NSTask alloc] init];    [task setLaunchPath:@"/bin/sh"];    NSArray *arguments = [NSArray arrayWithObjects:                          @"-c" ,                          [NSString stringWithFormat:@"%@", commandToRun],                          nil];    NSLog(@"run command:%@", commandToRun);    [task setArguments:arguments];    NSPipe *pipe = [NSPipe pipe];    [task setStandardOutput:pipe];    NSFileHandle *file = [pipe fileHandleForReading];    [task launch];    NSData *data = [file readDataToEndOfFile];    NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    return output;}

You can use this method like this:

NSString *output = runCommand(@"ps -A | grep mysql");


in the spirit of sharing... this is a method I use frequently to run shell scripts.you can add a script to your product bundle (in the copy phase of the build) and thenhave the script be read and run at runtime. note: this code looks for the script in the privateFrameworks sub-path.warning: this could be a security risk for deployed products, but for our in-house development it is an easy way to customize simple things (like which host to rsync to...) without re-compiling the application, but just editing the shell script in the bundle.

//-------------------------------------------------------(void) runScript:(NSString*)scriptName{    NSTask *task;    task = [[NSTask alloc] init];    [task setLaunchPath: @"/bin/sh"];    NSArray *arguments;    NSString* newpath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] privateFrameworksPath], scriptName];    NSLog(@"shell script path: %@",newpath);    arguments = [NSArray arrayWithObjects:newpath, nil];    [task setArguments: arguments];    NSPipe *pipe;    pipe = [NSPipe pipe];    [task setStandardOutput: pipe];    NSFileHandle *file;    file = [pipe fileHandleForReading];    [task launch];    NSData *data;    data = [file readDataToEndOfFile];    NSString *string;    string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];    NSLog (@"script returned:\n%@", string);    }//------------------------------------------------------

Edit: Included fix for NSLog problem

If you are using NSTask to run a command-line utility via bash, then you need to include this magic line to keep NSLog working:

//The magic line that keeps your log where it belongs[task setStandardInput:[NSPipe pipe]];

In context:

NSPipe *pipe;pipe = [NSPipe pipe];[task setStandardOutput: pipe];//The magic line that keeps your log where it belongs[task setStandardInput:[NSPipe pipe]];

An explanation is here: http://www.cocoadev.com/index.pl?NSTask