0

I have code like following, it's ok, but I have 2 question about it.

1) If I assign some illegal para to sh, for example @"ls - l", then the outString is null. That is to say, it can not capture the error warning "ls: -: No such file or directory ls: l: No such file or directory". How can I deal with it?

2) How can I implement this function: given the app's current directory is "/user/Doc", and I perform sh = @"cd /", then I perform sh = @"ls -l" to see the content under the "/" directory at next loop. But when new loop starts, the current directory resume to "/user/Doc". How can I remain the task environment of last loop?

Furthermore, can I remain a persistent task to run "/bin/sh",just like work on the Terminal directly?

NSString *sh = @"ls -l";
while(sh != @"end"){
    NSTask *shData = [[NSTask alloc] init];
    [shData setLaunchPath: @"/bin/sh"];

    NSArray *args;
    args = [NSArray arrayWithObjects: @"-c", sh, nil];
    [shData setArguments: args];

    NSPipe *myPipe;
    myPipe = [NSPipe pipe];
    [shData setStandardOutput: myPipe];
    [shData setStandardInput:[NSPipe pipe]];

    NSFileHandle *file;
    file = [myPipe fileHandleForReading];

    [shData launch];

    NSData *data1;    
    data1 = [file readDataToEndOfFile];

    NSString *outString;
    outString = [[NSString alloc] initWithData: data1 encoding: NSUTF8StringEncoding];

    NSLog(@"%@",outString);
}
Tom Jacky
  • 203
  • 1
  • 7
  • 20
  • For the working directory, why not just use `-[NSTask setCurrentDirectoryPath:]`? – Ken Thomases May 16 '12 at 16:08
  • That isn't what I need. My purpose is continuous run the task with different args, but require that the next run's environments is decided by the last run output. For example, after I run "cd /" task, I want to run "ls -l" to show all content under the directory "/" which is the result of running "cd /". – Tom Jacky May 17 '12 at 02:57
  • Apple's doc says:"An NSTask object can only be run once." If there is alternative way to make the shell subprocess retain and receive the args at runtime? – Tom Jacky May 17 '12 at 02:59
  • If you want a shell to which you can feed a sequence of commands, just don't pass "-c" and a command. Instead launch it without arguments or with "-s". Then write commands like "ls -l\n" (note the newline) to the pipe connected to standard input. – Ken Thomases May 17 '12 at 03:24
  • can you give some example codes? – Tom Jacky May 17 '12 at 15:09

1 Answers1

3
  1. That string is on standard error, not standard output. Since you don't check the error stream, you won't find it.

  2. That's not how subshells work. Google for "why is cd a shell builtin" for lots of information.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Thx,Carl. Could gvie me some eample code for the standard error check? – Tom Jacky May 16 '12 at 15:47
  • @TomJacky That would be `[shData setStandardError:myPipe];`. – Itai Ferber May 16 '12 at 16:08
  • There is a problem when reading both standard output and standard error. If you attempt to read one to EOF and then the other, you may lock up. The problem is that the subprocess may be attempting to write to the one that you're not reading. If it writes enough to fill the kernel buffer for the pipe, it will block waiting for the reader (this code) to read from it, but the reader is blocked waiting for the other pipe to be closed. You have to read from at least one of them asynchronously using something like `-[NSFileHandle readToEndOfFileInBackgroundAndNotify]`. – Ken Thomases May 16 '12 at 16:12
  • @CarlNorum The first issue is resolved, but i still puzzled with the second. Is my issue due to the NSTask feature "An NSTask object can only be run once"? – Tom Jacky May 17 '12 at 03:21