objective-ccocoanstasknspipe

NSTask with multiple pipe input


I'm trying to use pipes to handle a command that requires multiple inputs, but not quite sure how to do it. Here's a snippet of what I'm trying to do. I know how to handle the first input, but I'm at lost as to piping in the second input -newstdinpass

NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe pipe];

[task setLaunchPath: @"/bin/sh"];
[task setArguments: [NSArray arrayWithObjects: @"-c", @"/usr/bin/hdiutil chpass -oldstdinpass -newstdinpass /path/to/dmg", nil]];
[task setStandardInput:pipe];
[task launch];

[[pipe fileHandleForWriting] writeData:[@"thepassword" dataUsingEncoding:NSUTF8StringEncoding]];
[[pipe fileHandleForWriting] closeFile];

[task waitUntilExit];
[task release];

So I know using hdiutil in this manner is a bit of a hack, but in terms of pipes, am I going about it the correct way?

Thanks.

UPDATE: In case others are wondering about this, a quick solution to my problem is to pass in a null-terminated string as Ken Thomases had pointed out below. Use [[NSString stringWithFormat:@"oldpass\0newpass\0"] dataUsingEncoding:NSUTF8StringEncoding] into the pipe. Now, still need to learn how to bridge multiple NSTasks with pipes...


Solution

  • You can create multiple NSTasks and a bunch of NSPipes and hook them together, or you can use the sh -c trick to feed a shell a command, and let it parse it and set up all the IPC.

    Example :

    NSTask *task;
    task = [[NSTask alloc] init];
    [task setLaunchPath: @"/bin/sh"];
    
    NSArray *arguments;
    arguments = [NSArray arrayWithObjects: @"-c",
                         @"cat /usr/share/dict/words | grep -i ham | rev | tail -5", nil];
    [task setArguments: arguments];
    // and then do all the other jazz for running an NSTask.
    

    Reference : http://borkware.com/quickies/one?topic=nstask


    Now, as for a "proper" command execution function, here's one I'm usually using...

    Code :

    /*******************************************************
     *
     * MAIN ROUTINE
     *
     *******************************************************/
    
    - (void)runCommand:(NSString *)cmd withArgs:(NSArray *)argsArray
    {
        //-------------------------------
        // Set up Task
        //-------------------------------
    
        if (task) { [self terminate]; }
    
        task = [[NSTask alloc] init];
        [task setLaunchPath:cmd];
        [task setArguments:argsArray];
    
        [task setStandardOutput:[NSPipe pipe]];
        [task setStandardError:[task standardOutput]];
    
        //-------------------------------
        // Set up Observers
        //-------------------------------
    
        [PP_NOTIFIER removeObserver:self];
        [PP_NOTIFIER addObserver:self 
                        selector:@selector(commandSentData:) 
                            name: NSFileHandleReadCompletionNotification 
                          object: [[task standardOutput] fileHandleForReading]];
    
        [PP_NOTIFIER addObserver:self 
                        selector:@selector(taskTerminated:) 
                            name:NSTaskDidTerminateNotification 
                          object:nil];
    
        //-------------------------------
        // Launch
        //-------------------------------
        [[[task standardOutput] fileHandleForReading] readInBackgroundAndNotify];
    
        [task launch];
    }
    
    /*******************************************************
     *
     * OBSERVERS
     *
     *******************************************************/
    
    - (void)commandSentData:(NSNotification*)n
    {
        NSData* d;
        d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
    
        if ([d length])
        {
            NSString* s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
    
            NSLog(@"Received : %@",s);
        }
    
        [[n object] readInBackgroundAndNotify]; 
    }
    
    - (void)taskTerminated:(NSNotification*)n
    {
        [task release];
        task = nil;
    }