NSTask 不会终止

发布于 2024-10-13 07:25:43 字数 703 浏览 9 评论 0原文

我正在尝试使用 NSTask 运行 UNIX 'apropos' 命令。这是我的代码:

NSTask *apropos = [[NSTask alloc] init];
NSPipe *pipe = [[NSPipe alloc] init];
[apropos setLaunchPath:@"/usr/bin/apropos"];
[apropos setArguments:[NSArray arrayWithObjects:@"filename", @"match", nil]];
[apropos setStandardOutput:pipe];
[apropos launch];
[apropos waitUntilExit];

问题是它永远不会返回。我还尝试使用 Apple 的示例代码 (TaskWrapper),它返回输出(分三段),但它从未调用 processFinished 处理程序。

此外,appendOutput: 处理程序接收重复​​项。因此,例如,如果 apropos 返回:

1 2 3 4 5

我可能会收到这样的信息:

1 2 3

1 2 3 4

5

(分为 3 条附加消息)。

我注意到 Apropos 以一种可以在命令行中上下滚动的格式显示输出,而不是直接将数据直接输出到标准输出;如何通过 NSTask 和 NSPipe 可靠地读取此内容?

I'm trying to use NSTask to run the UNIX 'apropos' command. Here's my code:

NSTask *apropos = [[NSTask alloc] init];
NSPipe *pipe = [[NSPipe alloc] init];
[apropos setLaunchPath:@"/usr/bin/apropos"];
[apropos setArguments:[NSArray arrayWithObjects:@"filename", @"match", nil]];
[apropos setStandardOutput:pipe];
[apropos launch];
[apropos waitUntilExit];

The problem is that this never returns. I also tried using Apple's example code (TaskWrapper) and it returns the output (in three segments) but it never calls the processFinished handler.

Furthermore, the appendOutput: handler receives duplicates. So, for example, if apropos returns this:

1
2
3
4
5

I might receive something like this:

1
2
3

1
2
3
4

5

(grouped into 3 append messages).

I note that Apropos displays the output in a format where it's possible to scroll up and down in the command line instead of just directly outputting the data straight to standard output; how do I read this reliably through NSTask and NSPipe?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怪我太投入 2024-10-20 07:25:44

我刚刚测试了这个程序,它运行良好:程序终止,并且 /tmp/apropos.txt 包含 apropos 的输出。

#import <Foundation/Foundation.h>

int main()
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    NSTask *apropos = [[[NSTask alloc] init] autorelease];
    NSPipe *pipe = [[[NSPipe alloc] init] autorelease];
    NSFileHandle *readHandle = [pipe fileHandleForReading];
    [apropos setLaunchPath:@"/usr/bin/apropos"];
    [apropos setArguments:[NSArray arrayWithObjects:@"filename", @"match", nil]];
    [apropos setStandardOutput:pipe];
    [apropos launch];
    [apropos waitUntilExit];

    NSString *output = [[[NSString alloc]
        initWithData:[readHandle readDataToEndOfFile]
            encoding:NSUTF8StringEncoding] autorelease];

    [output writeToFile:@"/tmp/apropos.txt" atomically:YES
        encoding:NSUTF8StringEncoding error:NULL];

    [pool drain];
    return 0;
}

您是否有机会使用 NSLog() 来检查输出?如果是这样,您可能需要为 stdin 设置管道,如下所述 在我对 NSTask 相关问题的回答中。看来 NSLog()stderr 发送数据会影响 NSTask

I’ve just tested this program and it works fine: the program terminates and /tmp/apropos.txt contains the output of apropos.

#import <Foundation/Foundation.h>

int main()
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    NSTask *apropos = [[[NSTask alloc] init] autorelease];
    NSPipe *pipe = [[[NSPipe alloc] init] autorelease];
    NSFileHandle *readHandle = [pipe fileHandleForReading];
    [apropos setLaunchPath:@"/usr/bin/apropos"];
    [apropos setArguments:[NSArray arrayWithObjects:@"filename", @"match", nil]];
    [apropos setStandardOutput:pipe];
    [apropos launch];
    [apropos waitUntilExit];

    NSString *output = [[[NSString alloc]
        initWithData:[readHandle readDataToEndOfFile]
            encoding:NSUTF8StringEncoding] autorelease];

    [output writeToFile:@"/tmp/apropos.txt" atomically:YES
        encoding:NSUTF8StringEncoding error:NULL];

    [pool drain];
    return 0;
}

Are you by any chance using NSLog() to inspect the output? If so, you might need to set a pipe for stdin as explained in this answer of mine to an NSTask related question. It seems that NSLog() sending data to stderr affects NSTask.

久伴你 2024-10-20 07:25:44

使用您的原始代码,我想这是因为您没有读取命令的输出。管道的缓冲区大小有限,如果您不读取任务的输出,它最终可能会挂起,等待缓冲区清空。我对您尝试过的示例代码一无所知,所以我无法提供帮助。至于最后一个问题,apropos 仅在连接到终端时才使用寻呼机。您不是在模拟终端,因此不必担心。您可以通过运行 apropos another | 来证明这一点cat 在终端中并验证寻呼机未被调用。

With your original code, I would imagine it's because you're not reading the output of the command. The pipes only have a limited buffer size, and if you don't read the output of the task, it can end up hung waiting for the buffer to empty out. I don't know anything about the sample code you tried so I can't help there. As for the last question, apropos only uses the pager when it's connected to a terminal. You're not emulating a terminal, so you don't have to worry. You can prove this by running apropos whatever | cat in the terminal and verifying that the pager is not invoked.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文