views:

64

answers:

2

Is there a way that lets me run a shell script, and display the output in an NSTextView? I do not want any input from the user to the shell script at all, since is is just called to compile a buch of files. The shell script part works fine so far, but I just can't figure out how to run it and show the output in an NSTextView. I know a shell script can be run using system() and NSTask, but how do I get it's output into an NSTextView?

+1  A: 

NSTask has setStandardOutput method that accepts either NSFileHandle or NSPipe object. So if you create NSPipe object and set it as NSTask's standardOutput then you could use NSPipe's fileHandleForReading to get NSFileHandle from which, in turn, you'll be able to readDataToEndOfFile or readDataOfLength: you want. So something like this would do (code untested):

- (void)setupTask {
  // assume it's an ivar
  standardOutputPipe = [[NSPipe alloc] init];
  [myTask setStandardOutput:standardOutputPipe];
  // other setup code goes below
}

// reading data to NSTextField
- (void)updateOutputField {
  NSFileHandle *readingFileHandle = [standardOutputPipe fileHandleForReading];
  NSData *newData;
  while ((newData = [readingFileHandle availableData])) {
    NSString *newString = [[[NSString alloc] initWithData:newData encoding: NSASCIIStringEncoding] autorelease];
    NSString *wholeString = [[myTextField stringValue] stringByAppendingString:newString];
    [myTextField setStringValue:wholeString];
  }
  [standardOutputPipe release];
  standardOutputPipe = nil;
}
Eimantas
Depending on how long the task will run, it may be better to read the data in the background, using one of NSFileHandle's methods for that.
Peter Hosey
I am basically doing what you say above, and running the update output field in the background using a thread, the task runs, but I never see anyrthing in the textview. It is wired up correctly. Here's the code for running in the background: '[NSThread detachNewThreadSelector: @selector(updateOutputField:) toTarget:self withObject: nil];'It shows the output in the debugger, but on in the text field. Launching it is like this:[myTask setLaunchPath:@"/bin/sh"]; [myTask setArguments:[NSArray arrayWithObjects:scr], nil]]; [myTask setStandardOutput:standardOutputPipe]; [myTask launch];
Tristan Seifert
A: 

If you want wildcard expansion then pass your unix command to /bin/sh

- (NSString *)unixSinglePathCommandWithReturn:(NSString *) command {
    // performs a unix command by sending it to /bin/sh and returns stdout.
    // trims trailing carriage return
    // not as efficient as running command directly, but provides wildcard expansion

    NSPipe *newPipe = [NSPipe pipe];
    NSFileHandle *readHandle = [newPipe fileHandleForReading];
    NSData *inData = nil;
    NSString* returnValue = nil;

    unixTask = [[NSTask alloc] init];
    [unixTask setStandardOutput:newPipe];
    [unixTask setLaunchPath:@"/bin/csh"];
    [unixTask setArguments:[NSArray arrayWithObjects:@"-c", command , nil]]; 
    [unixTask launch];
    [unixTask waitUntilExit];
    int status = [unixTask terminationStatus];

    while ((inData = [readHandle availableData]) && [inData length]) {

        returnValue= [[NSString alloc] 
                      initWithData:inData encoding:[NSString defaultCStringEncoding]];

        returnValue = [returnValue substringToIndex:[returnValue length]-1];

        NSLog(@"%@",returnValue);
    }

    return returnValue;

}
blissapp