NSTask NSPipe - objective c command line help

匿名 (未验证) 提交于 2019-12-03 03:06:01

问题:

Here is my code:

task = [[NSTask alloc] init]; [task setCurrentDirectoryPath:@"/applications/jarvis/brain/"]; [task setLaunchPath:@"/applications/jarvis/brain/server.sh"];  NSPipe * out = [NSPipe pipe]; [task setStandardOutput:out];  [task launch]; [task waitUntilExit]; [task release];  NSFileHandle * read = [out fileHandleForReading]; NSData * dataRead = [read readDataToEndOfFile]; NSString * stringRead = [[[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding] autorelease]; 

So I'm trying to replicate this:

cd /applications/jarvis/brain/ ./server.sh 

but using NSTask in objective-c.

For some reason though, when I run this code, stringRead, returns nothing. It should return what terminal is returning when I launch the .sh file. Correct?

Any ideas?

Elijah

回答1:

Xcode Bug
There's a bug in Xcode that stops it from printing any output after a a new task using standard output is launched (it collects all output, but no longer prints anything). You're going to have to call [task setStandardInput:[NSPipe pipe]] to get it to show output again (or, alternatively, have the task print to stderr instead of stdout).


Suggestion for final code:

NSTask *server = [NSTask new]; [server setLaunchPath:@"/bin/sh"]; [server setArguments:[NSArray arrayWithObject:@"/path/to/server.sh"]]; [server setCurrentDirectoryPath:@"/path/to/current/directory/"];  NSPipe *outputPipe = [NSPipe pipe]; [server setStandardInput:[NSPipe pipe]]; [server setStandardOutput:outputPipe];  [server launch]; [server waitUntilExit]; // Alternatively, make it asynchronous. [server release];  NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile]; NSString *outputString = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease]; // Autorelease optional, depending on usage. 


回答2:

The solution above is freezing because it's synchronous. Call to [server waitUntilExit] blocks the run loop until the tasks is done.

Here's the async solution for getting the task output.

task.standardOutput = [NSPipe pipe]; [[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {     NSData *data = [file availableData]; // this will read to EOF, so call only once     NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);      // if you're collecting the whole output of a task, you may store it on a property     [self.taskOutput appendData:data]; }]; 

Probably you want to repeat the same above for task.standardError.

IMPORTANT:

When your task terminates, you have to set readabilityHandler block to nil; otherwise, you'll encounter high CPU usage, as the reading will never stop.

[task setTerminationHandler:^(NSTask *task) {      // do your stuff on completion      [task.standardOutput fileHandleForReading].readabilityHandler = nil;     [task.standardError fileHandleForReading].readabilityHandler = nil; }]; 

This is all asynchronous (and you should do it async), so your method should have a ^completion block.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!