NSTask not picking up $PATH from the user's environment
I don't know why this method returns a blank string:
- (NSString *)installedGitLocation {
NSString *launchPath = @"/usr/bin/which";
// Set up the task
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:launchPath];
NSArray *args = [NSArray arrayWithObject:@"git"];
[task setArguments:args];
// Set the output pipe.
NSPipe *outPipe = [[NSPipe alloc] init];
[task setStandardOutput:outPipe];
[task launch];
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
NSString *path = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
return path;
}
If instead of passing @"git"
as the argument, I pass @"which"
I get /usr/bin/which
returned as expected. So at least the principle works.
from the terminal
$ which which
$ /usr/bin/which
$
$ which git
$ /usr/local/git/bin/git
So it works there.
The only thing I can think of is that which
isn't searching through all the paths in my environment.
This is driving me crazy! Does anyone have any ideas?
EDIT: It looks like this is about setting up either NSTask or the user's shell (e.g., ~/.bashrc) so that the correct environment ($PATH) is seen by NSTask.
Try,
[task setLaunchPath:@"/bin/bash"]; NSArray *args = [NSArray arrayWithObjects:@"-l", @"-c", @"which git", nil]; [task setArguments: args];
This worked for me on Snow Leopard; I haven't tested on any other system. The -l (lowercase L) tells bash to "act as if it had been invoked as a login shell", and in the process it picked up my normal $PATH. This did not work for me if the launch path was set to /bit/sh, even with -l.
Running a task via NSTask uses fork()
and exec()
to actually run the task. The user's interactive shell isn't involved at all. Since $PATH
is (by and large) a shell concept, it doesn't apply when you're talking about running processes in some other fashion.
Is /usr/local/git/bin in your $PATH when you run the program? I think which
only looks in the user's $PATH.
Take a look at the question Find out location of an executable file in Cocoa. It looks like the basic problem is the same. The answer unfortunately isn't nice and neat, but there's some useful info there.
In Swift NSTask
is replaced by Process
but this is what it works for me:
let process = Process()
process.launchPath = "/bin/bash"
process.arguments = ["-l", "-c", "which git"]