1

I have it working. However, initially it appears to be waiting for input. How can I read what was output before it stops and is waiting for input?

task starts
stdout should post data for "sftp> " but nothing happens, its waiting for input
If I write "\n" to stdin
stdout notifies me of data available which ends up being "sftp> \n"

Here is how it's implemented:

[self.task = [[NSTask alloc] init];
[self.task setLaunchPath:executablePath];
[self.task setArguments: args];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(terminatedNotification:) name:NSTaskDidTerminateNotification object:self.task];

//reading
self.stdoutPipe = [NSPipe pipe];
self.task.standardOutput = self.stdoutPipe;
[self.stdoutPipe.fileHandleForReading waitForDataInBackgroundAndNotify];

//error
self.stderrorPipe = [NSPipe pipe];
self.task.standardError = self.stderrorPipe;
[self.stderrorPipe.fileHandleForReading waitForDataInBackgroundAndNotify];

/*
reading works perfect until I uncomment this section
//writing
self.stdinPipe = [NSPipe pipe];
self.task.standardInput = self.stdinPipe;
*/

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:self.stdoutPipe.fileHandleForReading];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:self.stderrorPipe.fileHandleForReading];
joels
  • 7,249
  • 11
  • 53
  • 94
  • May be the order is relevant, may be the input pipe has to be defined before the output pipe? I don't know. –  Jan 18 '13 at 22:00
  • I tried that. It didn't make a difference. – joels Jan 18 '13 at 22:09
  • Have a look at PseudoTTY.app and asynctask.m sample code over at: http://cocoadev.com/wiki/NSTask Please post a SSCCE, a Short, Self Contained, Correct (Compilable), Example. Thanks. –  Jan 25 '13 at 15:35

1 Answers1

3

Data written to a NSFileHandle is buffered. Only after the buffer has been flushed it will be available for reading on the other end of the pipe. The buffer is flushed if

  1. it is full and no more data would fit into it.
  2. a newline character ("\n") is written to it (autoflush).
  3. you flush it explicitly by calling - (void)synchronizeFile
Mecki
  • 125,244
  • 33
  • 244
  • 253
  • 1
    Thanks, great info. When I call [[self.task.standardOutput fileHandleForReading] synchronizeFile]; I get [NSConcreteFileHandle synchronizeFile]: Operation not supported – joels Jan 21 '13 at 16:59
  • 2
    @joels getting the same problem with `synchronizeFile`, and `\n` isn't sending any info to my `readabilityHandler` either. The only thing that works is `closeFile`, which is not what I want, because then I can't write more. What did you end up doing? – Aaron Ash Oct 05 '16 at 14:16
  • @joels You cannot synchronize the reading end of a pipe, only the writing end. The task that writes data to the file handle must synchronize it. If you call a task that writes to stdout but does not flush stdout (and is not sending new lines or has autoflush disabled), then you are out of luck as you, as the calling process, cannot force that buffer to be flushed. – Mecki Oct 05 '16 at 16:28