Emacs OS X: inferior shell $PATH inheritance - macos

Emacs manual says the following: Both M-! and M-| use shell-file-name to specify the shell to use. This variable is initialized based on your SHELL environment variable when Emacs is started. If the file name does not specify a directory, the directories in the list exec-path are searched; this list is initialized based on the environment variable PATH when Emacs is started. Your .emacs file can override either or both of these default initializations.
shell-file-name is set to /usr/local/bin/zsh
in terminal, echo $SHELL is usr/local/bin/zsh and echo $PATH is /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
However, M-x ! echo $SHELL is /bin/zsh and M-x ! echo $PATH is /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
Why is this so? How do I change it to be the same with the terminal $PATH?

I'm not sure of the specifics, but I think what you want is to set PATH in your .emacs, and that exec-path is used to search for your shell executable, not used by your shell executable.
Basically to put a desired directory at the front of $PATH, you want something like:
(setenv "PATH" (concat my-dir ":" (getenv "PATH")))
Some guides suggest you also do (add-to-list 'exec-path my-dir) when you do this in .emacs, I think just to keep the search paths of Emacs and its inferior shells in sync.
But hey, it's been almost a year, hopefully you've found a workaround by now.

Related

tuareg mode emacs ocaml not found

I am running emacs 24.3 on mac os x 10.9. I have installed the tuareg-mode for ocaml programming but am unable to compile using the command C-c C-b. On pressing the same, the minibuffer asks me about 'Caml toplevel to run: ocaml'. When I press enter it shows the error "Searching for program: No such file or directory, ocaml". What am I missing?
you need to setup PATH environment variable & the Emacs's exec-path variable to correct values. One possibility is to use something like (in your ~/.emacs):
(defun set-exec-path-from-shell-PATH ()
(let ((path-from-shell (shell-command-to-string "$SHELL -c 'echo $PATH'")))
(setenv "PATH" path-from-shell)
(setq exec-path (split-string path-from-shell path-separator))))
(when window-system (set-exec-path-from-shell-PATH))
to get the PATH from shell and both variables correctly. One advantage of this is that you will setup PATH only in one place - in your shell init script.
So I found this cool mode that autoloads the shell variables into emacs environment for mac users. Very handy:
https://github.com/purcell/exec-path-from-shell
Just install it and update your .emacs file and you are set.

Is there a way to get my emacs to recognize my bash aliases and custom functions when I run a shell command?

In my shell environment I have aliases and custom functions. When I am in an instance of emacs (I always use emacs -nw) and I execute a shell command (M-!) I cannot use them. This makes sense since I imagine it launches it's own subshell to do these... but is there a way (maybe in my .emacs) to get this to work? Perhaps even if it involved sourcing an environment by default before executing any shell command given?
Below are my comments about what I think was a related question:
I think both M-x shell-command and M-x compile execute commands in an inferior shell via call-process. Try the following in your .emacs (or just evaluate):
(setq shell-file-name "bash")
(setq shell-command-switch "-ic")
I notice that after evaluation of the above, .bashrc aliases are picked up for use by both M-x shell-command and M-x compile, i.e
M-x compile RET your_alias RET
should then work.
My environment: Emacs 24.1 (pretest rc1), OSX 10.7.3
Source
Have a read through http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files
For non-interactive shells, the only file that is sourced is the value of the BASH_ENV environment variable. You invoke emacs like BASH_ENV=~/.bashrc emacs if emacs will use bash for shell commands -- some programs specifically use "/bin/sh"
To get shell-command to read ~/.bashrc before executing the command per the technique described in https://stackoverflow.com/a/12228646/8869495, without potential side effects due to $BASH_ENV being defined for your entire Emacs session, try this in your ~/.emacs.d/init.el (or .emacs) file:
;; I want M-! (shell-command) to pick up my aliases and so run .bashrc:
(setq shell-file-name "bash-for-emacs.sh") ; Does this: BASH_ENV="~/.bashrc" exec bash "$#"
(setq shell-command-switch "-c")
As described by the comment in the second line, also install (in your $PATH) a script named bash-for-emacs.sh that contains:
#!/bin/bash
BASH_ENV="~/.bashrc" exec bash "$#"
Note that your ~/.bashrc might need to be changed to define non-interactive aliases even when [ -z "$PS1" ] is true (which indicates a non-interactive shell). That's the approach I'm taking for my own environment (such as it is), which is at https://github.com/jcburley/UnixHome.
Also, this assumes you want to use Bash as your Emacs-spawned shell, as I do.
We need to enable alias expansion in non-interactive shells, preferably only when they are called from emacs (to avoid causing subtle differences when we run other shells). What worked for me was to create two files: ~/.alias has all my aliases, e.g.
alias python python27
and ~/.aliasExpand has
source ~/.alias
shopt -s expand_aliases
I also, of course, replaced all my aliases in .bashrc with
source ~/.alias
Finally, I added this to my .emacs:
(setenv "BASH_ENV" "~/.aliasExpand")
I tried Keith Flower's solution (of making shells interactive), and I got
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
Note that I got this through Glenn Jackman's and Nicholas Dudebout's hints.
If you are willing to risk having all your shells have alias expansion and you don't mind running all your .bashrc for every emacs shell, you can simplify this to adding
shopt -s expand_aliases
to your .bashrc and
(setenv "BASH_ENV" "~/.bashrc")
to your .emacs
Setting shell-command-switch directly will substantially make shell-command much more sluggish (if you use many (ba|z)sh plugins), which is invoked by various non-interactive functions like shell-command-to-string, eshell-remote-command,... and numerous calls of it from other functions, all of which won't ever need .bashrc or .zshrc
For example, on my machine (and likely yours, too):
(benchmark-elapse (let ((shell-command-switch "-c")) (shell-command "")))
0.005170422
(benchmark-elapse (let ((shell-command-switch "-ic")) (shell-command "")))
0.242628824
;; Empty ~/.zshrc: 0.168341049
Therefore, we should opt find a way to use the interactive shell only when shell-command is called interactively
;;;###autoload
(defun my-shell-command-interactive-a (fn &rest args)
"Use interactive shell for `shell-command' when invoked interactively.
Setting the \"-i\" switch all the time will significantly slow
down `shell-command' because there may too many files to source."
(let ((shell-command-switch (if (called-interactively-p 'interactive)
;; Replace the first "-"
(replace-regexp-in-string
"\\(-\\).*\\'"
"-i"
shell-command-switch
nil
nil
1)
shell-command-switch)))
(apply fn args)))
(dolist (cmd '(shell-command async-shell-command))
(advice-add cmd :around #'my-shell-command-interactive-a))
Put the aliases and functions in .bashrc, not .bash_profile. The latter is only executed in login shells, the former is in all shells.

Emacs is ignoring my path when it runs a compile command

I'm trying to get a compile command (rake cucumber) to run with a specific ruby version on my Mac OS X system, I use rvm to do this currently in the terminal. My ~/.MacOSX/environment.plist has the correct path in it, but emacs insists on prepending to this path and therefore making it useless. I've also tried:
(when (equal system-type 'darwin)
(setenv "PATH" (concat "/Users/fearoffish/.rvm/bin:/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin:/Users/fearoffish/.rvm/bin"))
(push "/Users/fearoffish/.rvm/bin" exec-path)
(push "/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin" exec-path)
(push "/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin" exec-path)
(push "/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin" exec-path)
(push "/Users/fearoffish/.rvm/bin" exec-path))
It was the desperate attempt of an emacs beginner to get what I wanted. It still prepends in front of it, so my path ends up being:
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/Users/fearoffish/.rvm/bin:/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin
I don't want /usr/bin and others prepending, I want my path first and the emacs prepended path to be at the end, I reckon this would fix my problem.
I test this by simply opening Aquamacs and running meta-x compile and then echo $PATH.
Any ideas?
A small modification to the solution by sanityinc (couldn't find a way to enter it in the comments above -- is that just me?)
I use -l option to the shell to force a login shell (which reads .profile or .bash_profile), rather than an interactive shell (which only reads .bashrc).
I do some string trimming on the returned path (as inspection shows a newline sneaking in).
Modified code:
(defun set-exec-path-from-shell-PATH ()
(let ((path-from-shell
(replace-regexp-in-string "[[:space:]\n]*$" ""
(shell-command-to-string "$SHELL -l -c 'echo $PATH'"))))
(setenv "PATH" path-from-shell)
(setq exec-path (split-string path-from-shell path-separator))))
(when (equal system-type 'darwin) (set-exec-path-from-shell-PATH))
Everyone seems to have misunderstood the original issue: the path is already setup correctly in Emacs, and the correct path is already passed to the shell started by the compile command! So what gives? Here is the answer:
In MacOS X, there is a small tool called path_helper(1). It is called by default from /etc/profile, which is executed by Bash on shell startup. When you start a compilation from Emacs, it launches a shell (which by default is Bash on MacOS X), and therefore executes this path_helper tool. And here comes the key point: path_helper rearranges your path, moving the standard directories like /usr/bin in front of your custom added directories, no matter where you originally added them. Try this yourself by opening a shell and first having a look at what PATH is, and then execute /usr/lib/path_helper and have look at the resulting PATH!
The brute force solution for you might be to simply comment out the call to path_helper in /etc/profile. Note however that then you won't automatically get the paths in /etc/paths.d setup by path_helper, which is the tool's main purpose.
I don't have a Mac, so I cannot test this directly, but this can all be found in the *info* page Interactive Inferior Shell.
When you start a shell in Emacs, the process that gets spawned is the program in the Emacs variable explicit-shell-file-name (and if that is nil, the environment variables ESHELL and SHELL are used).
It then sends the contents of ~/.emacs_*shellname* (e.g. if your shell is csh, then ~/.emacs_csh would be sent over. Also, the appropriate .rc files for csh program is sourced, so you can update that as well (in my case .cshrc). Additionally, you can wrap customizations in the .rc file with a check for the environment variable INSIDE_EMACS (which which Emacs sets before it runs a shell).
You need to update those files to change the path in the shell, not the Emacs variable exec-path. exec-path - which is just a list of directories Emacs uses to find executable programs. The behavior of the executables are not affected by changes to exec-path.
I find the environment.plist scheme on Macs pretty ugly, so I use the following snippet, which assumes you want Emacs to use the same PATH that you see in your Terminal.app:
(defun set-exec-path-from-shell-PATH ()
(let ((path-from-shell (shell-command-to-string "$SHELL -i -c 'echo $PATH'")))
(setenv "PATH" path-from-shell)
(setq exec-path (split-string path-from-shell path-separator))))
(This works for me in Emacs 23; haven't tried it in other versions, but I'd expect it to work.)
try this maybe. replace path string with yours.
(add-to-list 'load-path "~/opt/swank-clojure/src/emacs")
As far as I observed, Emacs takes the path variable from the shell it is launched from, so one solution is to change $PATH in the shell before you launch Emacs.
One other approach I used, which is more flexible, is to use a Makefile and append a "source ~/script_that_set_path" in front of each make commands you have.
I have tried so many different approaches to this that ended up not using emacs to setup my compilation command environment.
What I do now is to create a run_helper.sh file that simply initializes a clean environment and then uses exec $* to execute the command passed as argument to run_helper.sh
This run_helper.sh is usually project specific, but I keep a template which I use to start with when I create a new project.
Then I simple run compile from emacs like bash run_helper.sh rspec path/to/tests for example.
If I am using this to run ruby tests, my helper initializes RVM to use the proper ruby and gemset. If I am using some other language it may just export required environment variables or perform some other initialization, but this way I can do it in bash script instead of always having to mess with emacs paths and elisp every time I start a new project.
Here's an example of a run_helper.sh file
#!/bin/bash
cd /Users/simao/Documents/sp
export DYLD_LIBRARY_PATH="/usr/local/mysql/lib:$DYLD_LIBRARY_PATH"
source "$HOME/.rvm/scripts/rvm" # This loads the proper ruby and gemset from .rvmrc
export RAILS_ENV=test
exec $*
This also makes my tests run faster because I have lots of stuff in my .zshrc that I don't want to load just to run some tests.
It worked for me with two things.
First I followed sanityinc advice
An improved and modified version of the code snippet is now published as elisp library called exec-path-from-shell; installable packages are available in Marmalade and Melpa
I still had a problem with compile commands. Valko Sipuli is right there was a problem involving path_helper.
I commented the corresponding line in /etc/profile and it did not help. Problem still there.
I don't use bash but zsh. Digging a little I found /etc/zshenv. This file also calls path_helper.
After commenting the path_helper section in /etc/zshenv my path is finally correct

Emacs and cygwin [duplicate]

I am running GNU Emacs on Windows so entering:
M-x shell
launches the Windows command-line DOS shell. However, I would like to instead be able to run the Cygwin Bash Shell (or any other non-Windows shell) from within Emacs. How can this be easily done?
shell-file-name is the variable that controls which shell Emacs uses when it wants to run a shell command.
explicit-shell-file-name is the variable that controls which shell M-x shell starts up.
Ken's answer changes both of those, which you may or may not want.
You can also have a function that starts a different shell by temporarily changing explicit-shell-file-name:
(defun cygwin-shell ()
"Run cygwin bash in shell mode."
(interactive)
(let ((explicit-shell-file-name "C:/cygwin/bin/bash"))
(call-interactively 'shell)))
You will probably also want to pass the --login argument to bash, because you're starting a new Cygwin session. You can do that by setting explicit-bash-args. (Note that M-x shell uses explicit-PROGRAM-args, where PROGRAM is the filename part of the shell's pathname. This is why you should not include the .exe when setting the shell.
The best solution I've found to this is the following:
;; When running in Windows, we want to use an alternate shell so we
;; can be more unixy.
(setq shell-file-name "C:/MinGW/msys/1.0/bin/bash")
(setq explicit-shell-file-name shell-file-name)
(setenv "PATH"
(concat ".:/usr/local/bin:/mingw/bin:/bin:"
(replace-regexp-in-string " " "\\\\ "
(replace-regexp-in-string "\\\\" "/"
(replace-regexp-in-string "\\([A-Za-z]\\):" "/\\1"
(getenv "PATH"))))))
The problem with passing "--login" as cjm suggests is your shell will always start in your home directory. But if you're editing a file and you hit "M-x shell", you want your shell in that file's directory. Furthermore, I've tested this setup with "M-x grep" and "M-x compile". I'm suspicious that other examples here wouldn't work with those due to directory and PATH problems.
This elisp snippet belongs in your ~/.emacs file. If you want to use Cygwin instead of MinGW, change the first string to C:/cygwin/bin/bash. The second string is prepended to your Windows PATH (after converting that PATH to an appropriately unixy form); in Cygwin you probably want "~/bin:/usr/local/bin:/usr/bin:" or something similar.
I use XEmacs with Cygwin, and can run bash from XEmacs relatively easily.
Here's the relevant section from init.el
;; Let's use CYGWIN bash...
;;
(setq binary-process-input t)
(setq w32-quote-process-args ?\")
(setq shell-file-name "bash") ;; or sh if you rename your bash executable to sh.
(setenv "SHELL" shell-file-name)
(setq explicit-shell-file-name shell-file-name)
(setq explicit-sh-args '("-login" "-i"))
One more important hint on this subject.
If you use Emacs shell mode and want both bash and cmd sometimes, set it up to use bash by default, because you can type cmd at bash and the resulting dos shell works just fine.
If you setup Emacs to use cmd as the shell (which is the way NT emacs installs), then dos shell works fine, but if you type bash or bash -i to run a bash shell, the resulting shell doesn't work right - see answer 0.
But it works fine if bash is the "first" shell emacs invokes.
You can run bash directly from the default Windows command-line shell within your Emacs *shell* buffer:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\temp>bash
bash
However, no command prompt is visible which can be disorienting resulting in your commands and their output results all blending together.
In addition, for some unknown reason, if you do enter a command and hit return, a return line character (\r) is appended to the end of your command statement causing a bash error:
ls
bash: line 1: $'ls\r': command not found
A workaround is to manually add a comment character (#) at the end of every command which effectively comments out the \r text:
ls #
myfile,txt
foo.bar
anotherfile.txt
This overall approach is far from ideal but might be useful if you want to drop into bash from Windows' native shell to do some quick operations and then exit out to continue working in Windows.
I'm using EmacsW32. C-h a shell$ gives a list of shell launching commands and the commands cmd-shell and cygwin-shell look interesting. Both commands need EmacsW32. They are also found in the menu: Tools > W&32 Shells.
If you run cygwin-shell for the first time, and if you have not setup cygwin path in Emacs, it leads you to the Customization page where you can setup the cygwin path by pressing Find button.
Since these approaches didn't work for me I got it the following way:
(I'm using NTEmacs which opens a dos shell by default, so perhaps your emacs behaves the same)
Create a windows environment variable named SHELL ('SHELL' not '$SHELL') and give it the path to bash.exe of your cygwin installation (for example c:\programs\cygwin\bin\bash.exe)
Now when doing M-x shell it opens a bash.
Regards,
Inno
In addition to #Chris Jones' answer about avoiding the --login argument to bash, I set the following command line arguments:
(setq explicit-bash-args '("--noediting" "-i"))
The --noediting option prevents interference with the GNU readline library and the -i option specifies that the shell is interactive. I also use the .emacs_bash file in my home directory for any emacs specific bash customizations.

How can I run Cygwin Bash Shell from within Emacs?

I am running GNU Emacs on Windows so entering:
M-x shell
launches the Windows command-line DOS shell. However, I would like to instead be able to run the Cygwin Bash Shell (or any other non-Windows shell) from within Emacs. How can this be easily done?
shell-file-name is the variable that controls which shell Emacs uses when it wants to run a shell command.
explicit-shell-file-name is the variable that controls which shell M-x shell starts up.
Ken's answer changes both of those, which you may or may not want.
You can also have a function that starts a different shell by temporarily changing explicit-shell-file-name:
(defun cygwin-shell ()
"Run cygwin bash in shell mode."
(interactive)
(let ((explicit-shell-file-name "C:/cygwin/bin/bash"))
(call-interactively 'shell)))
You will probably also want to pass the --login argument to bash, because you're starting a new Cygwin session. You can do that by setting explicit-bash-args. (Note that M-x shell uses explicit-PROGRAM-args, where PROGRAM is the filename part of the shell's pathname. This is why you should not include the .exe when setting the shell.
The best solution I've found to this is the following:
;; When running in Windows, we want to use an alternate shell so we
;; can be more unixy.
(setq shell-file-name "C:/MinGW/msys/1.0/bin/bash")
(setq explicit-shell-file-name shell-file-name)
(setenv "PATH"
(concat ".:/usr/local/bin:/mingw/bin:/bin:"
(replace-regexp-in-string " " "\\\\ "
(replace-regexp-in-string "\\\\" "/"
(replace-regexp-in-string "\\([A-Za-z]\\):" "/\\1"
(getenv "PATH"))))))
The problem with passing "--login" as cjm suggests is your shell will always start in your home directory. But if you're editing a file and you hit "M-x shell", you want your shell in that file's directory. Furthermore, I've tested this setup with "M-x grep" and "M-x compile". I'm suspicious that other examples here wouldn't work with those due to directory and PATH problems.
This elisp snippet belongs in your ~/.emacs file. If you want to use Cygwin instead of MinGW, change the first string to C:/cygwin/bin/bash. The second string is prepended to your Windows PATH (after converting that PATH to an appropriately unixy form); in Cygwin you probably want "~/bin:/usr/local/bin:/usr/bin:" or something similar.
I use XEmacs with Cygwin, and can run bash from XEmacs relatively easily.
Here's the relevant section from init.el
;; Let's use CYGWIN bash...
;;
(setq binary-process-input t)
(setq w32-quote-process-args ?\")
(setq shell-file-name "bash") ;; or sh if you rename your bash executable to sh.
(setenv "SHELL" shell-file-name)
(setq explicit-shell-file-name shell-file-name)
(setq explicit-sh-args '("-login" "-i"))
One more important hint on this subject.
If you use Emacs shell mode and want both bash and cmd sometimes, set it up to use bash by default, because you can type cmd at bash and the resulting dos shell works just fine.
If you setup Emacs to use cmd as the shell (which is the way NT emacs installs), then dos shell works fine, but if you type bash or bash -i to run a bash shell, the resulting shell doesn't work right - see answer 0.
But it works fine if bash is the "first" shell emacs invokes.
You can run bash directly from the default Windows command-line shell within your Emacs *shell* buffer:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\temp>bash
bash
However, no command prompt is visible which can be disorienting resulting in your commands and their output results all blending together.
In addition, for some unknown reason, if you do enter a command and hit return, a return line character (\r) is appended to the end of your command statement causing a bash error:
ls
bash: line 1: $'ls\r': command not found
A workaround is to manually add a comment character (#) at the end of every command which effectively comments out the \r text:
ls #
myfile,txt
foo.bar
anotherfile.txt
This overall approach is far from ideal but might be useful if you want to drop into bash from Windows' native shell to do some quick operations and then exit out to continue working in Windows.
I'm using EmacsW32. C-h a shell$ gives a list of shell launching commands and the commands cmd-shell and cygwin-shell look interesting. Both commands need EmacsW32. They are also found in the menu: Tools > W&32 Shells.
If you run cygwin-shell for the first time, and if you have not setup cygwin path in Emacs, it leads you to the Customization page where you can setup the cygwin path by pressing Find button.
Since these approaches didn't work for me I got it the following way:
(I'm using NTEmacs which opens a dos shell by default, so perhaps your emacs behaves the same)
Create a windows environment variable named SHELL ('SHELL' not '$SHELL') and give it the path to bash.exe of your cygwin installation (for example c:\programs\cygwin\bin\bash.exe)
Now when doing M-x shell it opens a bash.
Regards,
Inno
In addition to #Chris Jones' answer about avoiding the --login argument to bash, I set the following command line arguments:
(setq explicit-bash-args '("--noediting" "-i"))
The --noediting option prevents interference with the GNU readline library and the -i option specifies that the shell is interactive. I also use the .emacs_bash file in my home directory for any emacs specific bash customizations.

Resources