3

OK, I must be missing something very simple but here's what:

  • If I echo $PATH in the terminal, I'm getting /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/drkameleon which is correct

  • Now if I run an NSTask and try executing a simple bash script (/usr/bin/env bash myscript.sh) to echo $PATH, it prints /Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin

(I've even tried with getenv, or print the entire [[NSProcessInfo processInfo] environment] dictionary, but the PATH variable is simply... wrong)

What's going on? How can I have access to the real $PATH as seen in the terminal?

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • 1
    What happens if you try `bash -l` to make it run like a login shell? The contents of `$PATH` is often modified in a `.bashrc` file. – Lev Landau Nov 14 '14 at 09:52
  • 2
    Take a look at answers at http://stackoverflow.com/questions/386783/nstask-not-picking-up-path-from-the-users-environment , you will find your answer there – Mehul Thakkar Nov 14 '14 at 10:07
  • @LevLandau I discovered it almost the very same time you posted your comment. Thanks a lot! :-) – Dr.Kameleon Nov 14 '14 at 10:15

1 Answers1

5

When executing a command via NSTask, not your bash, zshell or whatever kind of shell you are using, is started. Hence the PATH (and other environment variables) are different from your environment variables when echoing them in the terminal.

Reason: NSTask uses fork() and exec() for command execution.

IMHO, there are two possible solutions for the problem.

1. You could set the wanted PATH via the setEnvironment:method of NSTask

Here is some untested example code, which should do the trick:

NSTask *task = //Configure your task
NSDictionary* env = [task environment];
NSString* currentPATH = env["PATH"];
NSString* yourPathExtension = @"/your/path";
env["PATH"] = (currentPATH != nil) ? [yourPath stringByAppendingFormat:@":%@", currentPATH] : yourPathExtension;
[task setEnvironment:env];

This adds :<old-PATH> after the current PATH from NSTask.

2. You could start /bin/bash within NSTask

task setLaunchPath:@"/bin/bash"];
NSArray *args = [NSArray arrayWithObjects:@"-l",
                 @"-c",
                 @"<your command here>",
                 nil];
[task setArguments: args];

This task will start /bin/bash with the PATH configured via ~/.bashrc etc. and execute the command within the bash.

Pro: Your command has all the usual environment variables of your bash

Con: You rely on the users PATH variable which can be quite different from yours which may lead to unexpected behavior.

Which solution is the best one for you depends on your use case. In your provided example, both approaches should work fine.

In general, according to the NSTask and NSProcessInfo documentation, the environment variables are equal to the variables of the process from which the application has been started. Hence you might solve your problem when starting your application from the bash.

TobiasMende
  • 741
  • 3
  • 8