Setting PATH and other environment variables

Hi,


What is the recommended and most compatible way to set the PATH and other environment variables globally? I would like:


- A method that works from Yosemite and later versions of the OS

- It should work for both GUI + command line applications.

- It should work for both local shell and also remote SSH shells

- It should work with System Integrity Protection enabled


Here's some of the things I've tried:


- Setting the variables in ~/.bash_profile - this only seems to apply to command line apps.

- Editing /etc/paths and /etc/paths.d/ - this only seems to apply to command line apps.

- It seems possible to set some environment variables globally using launchctl and a plist. E.g.


Create file: /Library/LaunchAgents/myvars.plist


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>Label</key>

<string>myvars</string>

<key>ProgramArguments</key>

<array>

<string>/bin/launchctl</string>

<string>setenv</string>

<string>MYVAR</string>

<string>/Users/me/whereever</string>

</array>

<key>RunAtLoad</key>

<true/>

</dict>

</plist>


And load with: launchctl load /Library/LaunchAgents/myvars.plist


This seems to work ok for environment variables other than PATH, for GUI and local shells, but not ssh. It has one other slight issue, in that it doesn't seem to work for applications that are reopened at login, if "Reopen windows when logging back in" is checked


- The "launchctl config" command seems to allow PATH to be set (after a reboot) for GUI apps, but it doesn't appear to work for the terminal. E.g:


sudo launchctl config user path /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/me/mydir


Any other others?


Thanks.

Post not yet marked as solved Up vote post of srce Down vote post of srce
16k views

Replies

Hello srce,

No GUI app should rely on environment variables. No setting on your Mac will ever apply to remote ssh connections. Those are separate machines. Beyond that, it is more user preference.

"No GUI app should rely on environment variables"


That may be fine to say that for native Mac apps, but in my case, its a port of a suite of GUI & command line Windows and Linux apps and they need to be interoperable. While looking around trying to find an answer, it seems this is a pretty common problem for porting s/w from other platforms, just no sensible solution.


"No setting on your Mac will ever apply to remote ssh connections"


It seems there used to be a way that you could export the environment in to your ssh shell:


eval $(launchctl export)


But the export subcommand seems to have been removed (despite it still being in the man page)

Post not yet marked as solved Up vote reply of srce Down vote reply of srce

That may be fine to say that for native Mac apps, but in my case, its a port of a suite of GUI & command line Windows and Linux apps and they need to be interoperable.

If you’re going to package a cross platform app for the Mac, you should consider the necessary environment variable support as part of the packaging process. For example:

  • You can include environment variables in the

    LSEnvironment
    property your
    Info.plist
    .
  • You can build a trampoline that loads up the required environment variables from a configuration file then execs the real executable.

Setting environment variables in all apps just so that they are visible in your specific set of cross-platform apps seems a bit odd.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

So there's no way to set the PATH variable and have it work both for GUI apps and in the Terminal?


Thanks.

Post not yet marked as solved Up vote reply of srce Down vote reply of srce

Hello again srce,

How were those apps ported? If they are X11 apps, then you would set the environment variables with a wrapper, the same way you would do it on Linux. Or at least, that was how we used to do it back in Solaris days. You would have a shell script "start_app.sh" or something and it would define all the environment variables you would need and launch the GUI via X. You could have multiple versions of the software installed and just run "start_app.sh" and it would bootstrap according to where you launched it from.


But that is how it is supposed to work in Linux, Solaris, and X. If these apps were partially ported to the Mac, or ported circa MacOS X 10.3 or something, then they are just wrong. The Mac doesn't work like that. You can hack it with launchctl, which you seem to have done, and it may work. (It might not work in a few of months though.)


I checked on 10.6 and launchctl did have a crude export functionality back then. I'm sure you could hack something up in a shell script pretty easily. Just go through the environment and spit out the commands to export all those variables, then send those commands over an ssh connection. I'm sure there has got to be some way to do that. I don't know of any way, but then I wouldn't ever try anything like that. An external system is going to have completely different paths and variables. There is no way an "export" like that would ever work. I suggest you identify the variables you need using something like the ssh "SendEnv" option. Again, you can write a little shell script to export just what you need and open an ssh connection in a properly configured environment.

With regards to ssh, I'm talking about ssh'ing in to the Mac. When you ssh in to a windows or linux box, you're able to get the same environment as you would on a local terminal. This doesn't appear to be the case for a Mac.


What I want to do, is not that unusual. Take dev tools for example. There are lots of IDEs out there, that can drive a variety of command line tools. These are packaged separately, as they come from different vendors. In order to point the IDE at the correct command line tools, you would set the PATH variable. And you want the path to be set for the GUI apps, as well as when you open a terminal, or ssh in to use them.


This seems to be a problem for a whole host of IDEs on OSX:


Intellij - http://depressiverobot.com/2016/02/05/intellij-path.html

Eclipse - http://stackoverflow.com/questions/13735231/eclipse-with-cdt-on-mac

Xamarin Studio - https://forums.xamarin.com/discussion/63218/how-do-i-control-the-path-used-by-xamarin-studio-on-osx-yosemite

http://serverfault.com/questions/16355/how-to-set-global-path-on-os-x

http://stackoverflow.com/questions/347286/what-are-the-various-files-that-could-have-path-declarations-for-os-x-terminal-i

etc.


Cheers.

Post not yet marked as solved Up vote reply of srce Down vote reply of srce

"If they are X11 apps, then you would set the environment variables with a wrapper, the same way you would do it on Linux. Or at least, that was how we used to do it back in Solaris days. You would have a shell script "start_app.sh" or something and it would define all the environment variables you would need and launch the GUI via X."


If the script is named .sh, then when double clicking in finder, it always opens the file in an editor, rather than executing it, so that doesn't work.

To have it executed, it seems it needs to be named .command. The problem with this approach, is a Terminal window is displayed and closing this window kills the child process. It seems this can be worked around by adding an & after the program name, and then using some Apple Script to close the window. E.g.:


export PATH=/whereever:$PATH

export MYVAR=whatever

myprog &

osascript -e 'tell application "Terminal" to close front window' > /dev/null 2>&1 &


The problem then is, is that you can't use this script from the Terminal, as that last command will close your Terminal window. So you need a separate way to run your program, which is a bit confusing.


Also, for variables like PATH, you really want this to be global, as this needs to be set not just for my apps, but those from other vendors as well, so they can find my programs, and vice versa.


Thanks.

That was an example from Solaris days, many years ago. Maybe modern GUI-oriented Linux has something fancier. I don't know.


If you want to have a well-designed system on the Mac, you are going to have to do things the "Mac way". AppleScript might be one solution, but you have to approach it from a developer, not a user, perspective. (And the rumors are that Apple Script is going away.) But since you are a developer, you aren't limited by that. If you want an icon that can be double-clicked from the Finder, just make one. You can set any environment variables you want and then start child processes in that new environment. You don't want to go back out to the Terminal and try to make it do something.


But the bottom line is that you just don't use environment variables on a Mac. If you have Linux software ported to the Mac, that's fine. Set PATH or anything else for it and let it go. But trying to write Linux software that runs Mac software is just not going to work. The rumors aren't just that Apple Script is going away, the entire command line environment might go away too. Then what are you going to do? As far as Apple is concerned, the world is iOS, and a few greybeards running macOS who haven't retired - yet. From a systems perspective going forwards, you should assume an iOS-style platform.


You don't even need to use PATH and other environment variables on Solaris/Linux/etc. anyway. That is just convention, i.e. the way everyone does it. This is the Mac, people don't do it that way. If you are just porting software, then there are plenty of examples above to hack things up and make it work. But you are talking about making the Mac work like a foreign system and assuming you have some other vendors who are going to play along. I don't see that happening.

>recommended and most compatible way to set the PATH and other environment variables globally


Focusing on that request only, as there is apparently no fitzal, so your plist is a good start, at least - Seen this SO thread?


stackoverflow.com/questions/25385934/…

"If you have Linux software ported to the Mac, that's fine. Set PATH or anything else for it and let it go"


This is all I'm trying to do. But as indicated, it's doesn't seem to be possible to do in a simple and consistent way.

So is there a solution to this or not? It's absurd that GUI programs on macOS can't run command line tools that aren't pre-installed.

For the record, the application I'm running DOES have a configuration to point it to the path of the tool I want to run. The problem is that when it runs this tool, the path is inherited from the GUI app and so later when the tool that is directly invoked wants to run other command line tools it fails. The tool works fine when invoked from a regular command line, so there is no motivation for the tool developers to do anything about this. The PATH is the standard way to make command line tools accessible and it works for everything else. The decision to disallow configuring the PATH for GUI apps causes a lot of headaches.

The problem is that when it runs this tool, the path is inherited from the GUI app and so later when the tool that is directly invoked wants to run other command line tools it fails.

Have you tried wrapping the tool in a shell script that sets the path before invoking the real tool?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"