【问题标题】:NSTask NSPipe - objective c command line helpNSTask NSPipe - 目标 c 命令行帮助
【发布时间】:2011-03-27 12:41:56
【问题描述】:

这是我的代码:

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 文件时,它应该返回终端返回的内容。对吗?

有什么想法吗?

以利亚

【问题讨论】:

  • 您确定 server.sh 脚本输出标准输出吗?也许您也应该连接 stderr 并查看其中是否包含任何内容。您可能还需要考虑在任务运行时从管道读取数据,因为如果它在您不读取时尝试向管道打印太多,并且缓冲区已填满,则任务将在下次尝试时挂起输出任何东西。
  • 我不确定。你能给我举个例子吗?是的,我删除了 [task release] 和 [task waitUntilExit]。同样的问题。
  • 您是在以编程方式(或在 gdb 中)检查 stringRead 的内容,还是尝试使用 NSLog 或其他方式将它们打印出来?如果您正在使用 NSLog 并且根本看不到任何输出,请在 Applications > Utilities 中检查控制台日志以获取输出。作为 NSTask 运行的 Shell 脚本可以使 Xcode 控制台输出停止工作。除此之外,我同意凯文的意见,以检查是否存在标准错误(只需添加第二个管道并将其设置为任务的标准错误),并且不依赖管道能够缓冲所有任务的输出。
  • 以编程方式并通过 NSRunAlertPanel();只是为了测试。好的。我也会试试的。输出还有哪些其他选项?你能发布任何可能有帮助的例子吗?
  • 我试过了,同样的问题....有什么想法吗?

标签: objective-c nsstring terminal nstask


【解决方案1】:

Xcode 错误
Xcode 中有一个错误,它会在启动使用标准输出的新任务后停止打印任何输出(它收集所有输出,但不再打印任何内容)。您将不得不调用 [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.

【讨论】:

  • 这似乎也冻结了我的代码......嗯......还有其他想法吗?
  • 而且,我尝试输入 echo "hello world" 它返回空白......并且日期返回空白。
  • 即使[server setStandardInput:[NSPipe pipe]]?这有点奇怪。您是否逐字复制了我的代码?试一试,看看它是否适用于只包含echo "Hello World"; pwd | ls 的文件。如果还是不行,请告诉我们您使用的是哪个版本的 Xcode,并查看将字符串写入文件是否会产生任何输出(可能只是 Xcode 终端不再打印任何输出)。
  • 几年后这个错误似乎重新出现了,这个答案救了我!谢谢!
  • @PokeyMcPokerson 太好了!很高兴我能先发制人地提供帮助。 ;)
【解决方案2】:

上面的解决方案是冻结的,因为它是同步的。 调用[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 块设置为 nil;否则,您将遇到高 CPU 使用率,因为读取将永远不会停止。

[task setTerminationHandler:^(NSTask *task) {

    // do your stuff on completion

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

这都是异步的(你应该异步执行),所以你的方法应该有一个 ^completion 块。

【讨论】:

  • 完美。正在寻找块 API 的示例。
猜你喜欢
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-30
  • 2012-12-07
  • 1970-01-01
相关资源
最近更新 更多