2010-08-09 69 views
10

这里是我的代码:NSTask NSPipe - 目标C命令行帮助

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]; 

所以我想复制这样的:

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

但在Objective-C使用NSTask。

由于某些原因,当我运行此代码时,stringRead,不会返回任何内容。它应该返回当我启动.sh文件时终端正在返回的内容。正确?

任何想法?

利亚

+0

你确定server.sh脚本输出标准输出吗?也许你应该把stderr连接起来,看看它是否包含任何东西。 您可能还想考虑在任务运行时从管道读取数据,因为如果在您未读取时尝试向管道打印过多且缓冲区填满,则下次任务将挂起它会尝试输出任何东西。 – 2010-08-09 21:07:34

+0

我不确定。你能告诉我一个例子吗?是的,我删除了[任务发布]和[任务waitUntilExit]。同样的问题。 – objectiveccoder001 2010-08-09 21:23:54

+0

你是否以编程方式(或在gdb中)检查stringRead的内容,还是试图使用NSLog或其他东西打印出来?如果您使用的是NSLog并且根本看不到输出,请检查您的输出的“应用程序”>“实用程序”中的控制台日志。 Shell脚本作为NSTask运行,可以使Xcode控制台输出停止工作。 除此之外,我第二凯文的意见,以检查是否有标准错误的东西(只需添加第二个管道,并将其设置为您的任务的标准错误),并且不依赖于管道能够缓冲所有你的任务的输出。 – puzzle 2010-08-09 21:39:40

回答

19

Xcode的错误
有一个在Xcode中,从后使用标准输出新任务启动打印任何输出停止一个bug(它收集所有输出,但不再打印任何东西)。你将不得不打电话[task setStandardInput:[NSPipe pipe]]让它再次显示输出(或者,也可以将任务打印到stderr而不是stdout)。


建议最终的代码:

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. 
+0

看起来这似乎也冻结了我的代码......呵呵......其他想法呢? – objectiveccoder001 2010-08-13 04:06:50

+0

而且,我试图在回声“你好世界”它返回空白....日期回复空白。 – objectiveccoder001 2010-08-13 04:09:50

+0

即使使用'[server setStandardInput:[NSPipe pipe]]'?这有点奇怪。你是否逐字复制了我的代码?试试吧,看看它是否可以与只包含'echo“Hello World”的文件一起工作; pwd | ls'。 如果它仍然不起作用,请告诉我们您正在使用的Xcode的版本,并查看是否将字符串写入文件会生成任何输出(可能只是Xcode终端不打印更多输出)。 – 2010-08-13 08:15:21

9

将溶液上方冻结,因为它是同步的。 致电[server waitUntilExit]会阻止运行循环,直到完成任务。

以下是获取任务输出的异步解决方案。

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]; 
}]; 

也许你想重复一遍上面的task.standardError

重要:

当任务结束,你必须设置readabilityHandler块零;否则,你会遇到高CPU使用率,因为阅读永远不会停止。

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

    [task.standardOutput fileHandleForReading].readabilityHandler = nil; 
    [task.standardError fileHandleForReading].readabilityHandler = nil; 
}]; 

这是所有异步(你应该这样做async),所以你的方法应该有一个^完成块。

+0

完美。正在寻找一个块API的例子。 – uchuugaka 2015-05-23 07:47:07