Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top