Async execution of shell command not working properly

心不动则不痛 提交于 2019-12-02 12:34:26

问题


So, this is my code :

- (void)runCmd:(NSString *)cmd withArgs:(NSArray *)args
{
    NSLog(@"\nRunning ::\n\tCmd : %@\n\tArgs : %@",cmd, args);
    [theSpinner start];
    if (task)
    {
        [task interrupt];

    }
    else
    {
        task = [[NSTask alloc] init];
        [task setLaunchPath:cmd];

        [task setArguments:args];

        [pipe release];

        pipe = [[NSPipe alloc] init];
        [task setStandardOutput:pipe];

        NSFileHandle* fh = [pipe fileHandleForReading];

        NSNotificationCenter* nc;

        nc = [NSNotificationCenter defaultCenter];
        [nc removeObserver:self];
        [nc addObserver:self 
               selector:@selector(dataReady:) 
                   name:NSFileHandleReadCompletionNotification 
                 object:fh];
        [nc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:fh];
        [nc addObserver:self 
               selector:@selector(taskTerminated:) 
                   name:NSTaskDidTerminateNotification 
                 object:task];

        [task launch];
        [fh readInBackgroundAndNotify];
    }
}

- (void)dataAvailable:(NSNotification*)n
{
    NSLog(@"Data Available : %@",n);
}

- (void)dataReady:(NSNotification*)n
{
    NSData* d;

    d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];

    NSLog(@"Data Ready : %@",n);

    if ([d length])
    {
        NSLog(@"Data Ready : %@",[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]);
    }
}

- (void) taskTerminated:(NSNotification*)note
{
    NSLog(@"Task Terminated : %@",note);
    [task release];
    task = nil;
    [theSpinner stop];

    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
    [alert setMessageText:[NSString stringWithFormat:@"Command finished"]];

    [alert runModal];
}

I've tried running a command (e.g. the php interpreter at /usr/bin/php) with arguments (e.g. the file to be interpreted by php test.php).

The thing is :

  • The script runs fine
  • BUT, I'm receiving a Data Ready and Task Terminated notification BEFORE I've managed to get all the output. (I mean, the dataReady: function fetches just the first part of the
    output and the rest of it is nowhere to be found...)

I basically want to be reading, asynchronously, all output - WHILE the command is running.

Any Ideas? What am I doing wrong?

Thanks!


回答1:


You use readInBackgroundAndNotify to schedule your reading. This method reads only one buffer full of data and notifies. You either need to call readInBackgroundAndNotify in your notification method again to read more data or you need to use readToEndOfFileInBackgroundAndNotify if you want to receive all the data at once.




回答2:


There's a new API since 10.7, so you can avoid using NSNotifications.

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

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


来源:https://stackoverflow.com/questions/9965360/async-execution-of-shell-command-not-working-properly

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