How can I run Cygwin Bash Shell from within Emacs? - windows

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.

Related

MSYS2 inferior shell in Emacs on Windows

Trying to launch an inferior shell (M-x shell) in Emacs on Windows that connects to MSYS2.
I found this snippet from Mastering Emacs - Running Shells in Emacs Mastering Emacs, and adapted it:
(setq explicit-shell-file-name "D:/msys64/usr/bin/bash.exe")
(setq shell-file-name "bash")
(setq explicit-bash.exe-args '("--login" "-i")) <- Have also tried -c, and without "--login"
(setenv "SHELL" shell-file-name)
(add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m)
I get the following:
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
]0;~
me#computer MSYS ~
$
So I have some extra goofy characters and an inappropriate command passed to the MSYS shell, but this is progress! MSYS2 + Emacs on Windows would be AMAZING.
The problem is -i for Bash. It means interactive, so Bash attempts to configure terminal with ioctl which is nonsense for native Windows Emacs. Strip -i in native Emacs when you are using MSYS2 Bash.

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.

Garbage characters in my Windows Emacs shell. . . not sure what's wrong

I'm running GNU Emacs (23.1.1) on Windows and when I run a cygwin shell inside emacs I get garbage like the following, after each command:
^[]0;/cygdrive/c/emacs-23.1/bin
^[[32user#HOST [33m/cygdrive/c/emacs-23.1/bin[0m
Note: I've replaced my real user and host name with user/HOST.
I've found a few links that describe how to set up emacs with cygwin on Windows including this one on SO:
How can I run Cygwin Bash Shell from within Emacs?
That hasn't helped. As of right now, I don't have anything referencing shells in my .emacs file except for this:
;; For the interactive shell
(setq explicit-shell-file-name "bash")
So I'm not even sure how emacs is finding my cygwin shell. Any help is appreciated. Thanks.
Try adding these lines to your .emacs file
(autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t)
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
I'm not sure if these are the correct ones but let me know (as my .emacs file has gotten quite large over the years)

Getting Windows 7 SUA's bash shell working with emacs (EmacsW32)?

Having recently purchased Windows 7 Ultimate in order to gain access to the SUA - http://www.suacommunity.com - subsystem, I have been struggling to get SUA's bash utility (/usr/local/bin/bash) working with EmacsW32. SUA comes with ksh and csh by default, so I installed a community bundle to obtain the bash process.
M-x shell normally invokes a shell process and pipes stdio through an Emacs buffer. This works well with Cygwin. I have tried adjusting emacs variables like w32-shell-* to point it at the SUA bash executable, and also tried invoking bash via the posix.exe tool provided with SUA. I often see that the file descriptors associated with the bash process are deleted as soon as the process is created by EmacsW32.
Cygwin is very slow compared to SUA, so I am very keen to get this facility working with the EmacsW32 + SUA combo. Any tips, experience, solutions would be appreciated.
I don't know the w32-shell-* variables. Maybe you could show some code to illustrate what you mean.
I also don't know SUA.
I use GNU emacs v22 on Windows, and I run powershell as an inferior shell. I had some difficulties initially, similar to yours, and solved them with a better understanding of how to start the shell. Maybe this will help you.
I use these variables:
(setq explicit-shell-file-name
"c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe")
(setq explicit-powershell.exe-args
'("-Command" "-" )) ;; interactive, but no command prompt
I had difficulty until I realized two things:
if you don't specify command-line arguments for the shell process, emacs silently defaults to using -i. In the case of powershell, that argument was either not supported or it did something other than what I wanted (I forget). So I had to explicitly set the arguments to invoke the shell.
the name of the variable for specifying arguments to the shell, depends on the name of the program used to start the shell. This isn't documented as far as I know (unless you consider the source code to be documentation!). If you're on Linux and running sh, then the variable is explicit-sh-args. If bsh, then explicit-bsh-args. If you're on Windows, you need to use the proper name of the exe, including the .exe suffix. It makes for a strange looking variable name, but it works.
The full code to start powershell as an inferior emacs shell is like this:
;; get a name for the buffer
(setq buffer (get-buffer-create "*PowerShell*"))
(let ((tmp-shellfile explicit-shell-file-name))
(setq explicit-shell-file-name
"c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe")
(setq explicit-powershell.exe-args
'("-Command" "-" )) ; interactive, but no command prompt
;; launch the shell
(shell buffer)
; restore the original shell
(if tmp-shellfile
(setq explicit-shell-file-name tmp-shellfile)))
Maybe something like that would work for you.

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.

Resources