9

The terminal natively on Mac i.e. spawned through Spotlight or Launchpad, adopts the desired environment variables including the customization in ~/.bash_profile. But when I run Emacs (Emacs.app taken from Emacs For Mac OS X) and spawn shell inside it (using either shell, eshell or term), the shells doesn't adopt the same environment variables as mentioned earlier.

I realize that the shell adopts its environment from the process that launches it and it is because of this that the values of shell's environment variable the same as those of Emac (e.g. (getenv "PATH"))

Venturing inside the content of Terminal.app and Emacs.app did not get me lucky.

How can I automatically get the same environment variable I get in Terminal.app in the shell spawned inside Emacs? And I do not prefer launching Emacs from the terminal.

(I realize that this is too MacOSX-ish and the answers could propose solutions/tweaks that are totally outside of Emacs. But the question concerns Emacs therefore I chose this site)

  • If you start Emacs.app from a Terminal window do you see the correct environmental variables? – Melioratus Oct 09 '15 at 23:10
  • That way the environment variables are more rich but not the same as that in the terminal from which it was launched. The customizations (aliases etc) in the ~/.bash_profile are not read. @Melioratus – Bleeding Fingers Oct 10 '15 at 12:06
  • 1
    Weird. My `~/.bash_profile` is read correctly when I execute `Emacs.app` like this `/Applications/Emacs.app/Contents/MacOS/Emacs . &` using `Terminal.app`. – Melioratus Oct 10 '15 at 22:31
  • Just double checked that my aliases work too. – Melioratus Oct 10 '15 at 22:37

3 Answers3

5

I recently started using emacs outside of the terminal which was causing me some PATH issues. I had tried setting it by adding (getenv "PATH") to my exec-path, among other things that ultimately never worked.

I ended up installing the exec-path-from-shell package via melpa. It works by using your $SHELL environment variable to ask your shell to print out your $PATH and copying the result.

Edit: Here's the code I use

;; I set this at the beginning of my init.el for other mac specific settings
(defconst *is-a-mac* (eq system-type 'darwin))

;; Later on, after loading exec-path-from-shell package
(if *is-a-mac*
    (add-hook 'after-init-hook 'exec-path-from-shell-initialize))
Steven
  • 209
  • 4
  • 6
  • 1
    Please describe how this answer answers the question. E.g., in what way does installing that package help? – Drew Oct 20 '15 at 00:22
5

Like Mark said, Terminal and iTerm 2 invoke shells as login shells by default, so that Bash reads ~/.bash_profile but not ~/.bashrc, but M-x shell and M-x term invoke shells as non-login shells, so that Bash reads ~/.bashrc but not ~/.bash_profile. Either add . ~/.bash_profile to ~/.bashrc and keep using ~/.bash_profile as your Bash configuration file, or add . ~/.bashrc to ~/.bash_profile and start using ~/.bashrc as your Bash configuration file.

To make shell-command and shell-command-on-region read ~/.bash_profile, add -l to shell-command-switch:

(setq shell-command-switch "-lc")

You can set an OS X wide default path by for example saving a property list like this as ~/Library/LaunchAgents/startup.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>startup</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>launchctl setenv PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

The new path should be shown in terminal applications, Emacs, and other applications after you log out and back in. This method does not change the path in applications that are opened as login items or that are reopened at login after a forced shutdown. If you have Emacs, a terminal application, or other applications where you want to change the path in login items, you'll have to remove them.

nisetama
  • 241
  • 2
  • 4
4

Given the actual title here "How to make terminal/shell spawned inside Emacs running on a Mac inherit the environment variables of the native terminal?" you can't as Emacs will not have the Terminal.app as a super process at any level so Emacs cannot inherit anything form the shell in Terminal.app. You have to make the environment the same by sourcing the same files.

Building on this answer on AskDifferent

You need to note what the startup files for bash are. ~/.bash_profile is read in a login shell ~/.bashrc when another shell starts.

Cocoa Emacs is a GUI and when it runs it runs in a subprocess where nothing has run a login shell so it its environment there is nothing that has sourced ~/.bash_profile. Emacs will start a non login shell so anything in ~/.bashrc will be read.

This sort of thing is why is recommended in the bash manual to have this in ~/,bash_profile

if [ -f ~/.bashrc ]; then . ~/.bashrc; fi 

and put your environment settings in ~/.bashrc

As to why /Applications/Emacs.app/Contents/MacOS/Emacs . works in the terminal. Terminal.app defaults to running a shell in login mode and so that shell has sourced ~/.bash_profile and emacs is a subprocess of that shell and so inherits its environment. So in this case you do inherit from the shell in Terminal.app

Note X11 differs as you run it from a shell so that shell has environment variables as that shell is started as a login one.

mmmmmm
  • 491
  • 1
  • 4
  • 19