3

I run a simple grep command in my Cocoa app like so:

NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/grep"];

NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"foo", @"bar.txt", 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 (@"grep returned:\n%@", string);

[string release];
[task release];

However, I am somewhat curious to know how commands entered through terminal, which don't give out an output and are not executed promptly unless exited with something like Control + C can be run with this technique. Something like running java -jar server.jar where it keeps running until quit out of the session. How would I do something like that where the session is not automatically ended once the command has been launched?

Would I just need to comment out the part where it releases the NSTask? Any suggestions would be nice!

jscs
  • 63,694
  • 13
  • 151
  • 195
lab12
  • 6,400
  • 21
  • 68
  • 106

1 Answers1

6

When using NSTask with an underlying program that doesn’t exit immediately:

  1. You shouldn’t use -[NSFileHandle readDataToEndOfFile] since there is no end of file. Instead, you should use -[NSFileHandle readInBackgroundAndNotify] to read the standard output pipe of that task in the background, and be notified when data is available;

  2. You should use -[NSTask release] only when you’ve determined that the task shouldn’t run any more. In that case, prior to releasing the task, you should send its standard input the command that causes the underlying program to exit (e.g. the characters equivalent to control-d), or send it -terminate or -interrupt.

  3. You shouldn’t use -waitUntilExit unless you’ve spawned a secondary thread to deal with that task.

  • 1
    Really, you shouldn't be using `NSTask` for this at all. Use `Launchd` instead as it'll allow the server task to be maintained externally to your application and, generally, is designed to exactly serve the needs described. Bavarious's answer, though, is completely correct if you *do* want to use `NSTask`. – bbum May 29 '11 at 05:02
  • Ahh. Well that was the only example I had in my mind at the time. I'm not actually using it for a server type situation. – lab12 Jun 15 '11 at 00:30
  • 1
    none of these answers is complete… HOW "should you send its standard input the command that causes the underlying program to exit (e.g. the characters equivalent to control-d)"? AND HOW should you "Use Launchd instead"? As far as I know.. launchd has NO mechanism to watch a parent process lifecycle, and you can easily end up with zombie children. Not cute. – Alex Gray Jan 07 '12 at 00:33