ShellMode

For editing shell scripts, see ShMode.

Use ‘M-x shell’ to invoke a shell. The shell is an external program, and shell mode inherits the ability to interact with the program and its basic behaviors from ComintMode. If you want to use a shell written entirely in elisp use ‘M-x eshell’, see eshell. To invoke another shell, use ‘C-u M-x shell’.

Removing ^M Characters

Change the way ComintMode (the basis of ShellMode) treats the input by adding a filter function. Put this in your ~/.emacs file:

  (add-hook 'comint-output-filter-functions
            'comint-strip-ctrl-m)

However, cygwin-builds of bash since 2001-06-06 seem to confuse Emacs. There is an elegant solution, however: Tell Emacs that the bash process is returning DOS end-of-line bytes:

 (add-to-list 'process-coding-system-alist
              '("bash" . (undecided-dos . undecided-unix)))
 

This way, bash doesn’t get ^M from Emacs, but Emacs removes ^M it gets from bash. You no longer need to add ‘comint-strip-ctrl-m’ to the filter functions.

Setting Up a Cygwin Shell

For some instructions on how to setup the cygwin shell with emacs, see http://www.khngai.com/emacs/cygwin.php

Another good help is setup-cygwin.el.

In any case, you need cygwin-mount.el, but be aware of the different versions on the web (see CygwinMountVersions).

Invoking Multiple Shells, and Defining New Shells

Here is a a way to define new shell buffers using the usual ‘shell’ command. The point is that I don’t want to bother of the buffer’s name. So one press f7 to go to a shell buffer (if needed the command will start a new process), further uses of f7 in this buffer will cycle through the existing shell buffers. If you want a new shell buffer press C-u f7. – Matthias

 (global-set-key [f7] 'alt-shell-dwim)
 (defun alt-shell-dwim (arg)
   "Run an inferior shell like `shell'. If an inferior shell as its I/O
 through the current buffer, then pop the next buffer in `buffer-list'
 whose name is generated from the string \"*shell*\". When called with
 an argument, start a new inferior shell whose I/O will go to a buffer
 named after the string \"*shell*\" using `generate-new-buffer-name'."
   (interactive "P")
   (let* ((shell-buffer-list
 	  (let (blist)
	     (dolist (buff (buffer-list) blist)
	       (when (string-match "^\\*shell\\*" (buffer-name buff))
	 	(setq blist (cons buff blist))))))
	  (name (if arg
	 	   (generate-new-buffer-name "*shell*")
	 	 (car shell-buffer-list))))
     (shell name)))

The command above didn’t work for me, so I modified the original shell-dwim code.

First, you’ll want to customize same-window-regexps to include "\\*shell.*\\*\\(\\|<[0-9]+>\\)" to make sure that when you cycle through the shell buffers, they all stay in the same window. Then, put shell-dwim and the helper my-filter in your .emacs and bind to a key (f7, as suggested above, is one good option).

 (defun my-filter (condp lst)
     (delq nil (mapcar (lambda (x) (and (funcall condp x) x)) lst)))
 (defun shell-dwim (&optional create)
    "Start or switch to an inferior shell process, in a smart way.  If a                                                         
  buffer with a running shell process exists, simply switch to that buffer.                                                      
  If a shell buffer exists, but the shell process is not running, restart the                                                    
  shell.  If already in an active shell buffer, switch to the next one, if                                                       
  any.  With prefix argument CREATE always start a new shell."
    (interactive "P")
    (let ((next-shell-buffer) (buffer)
          (shell-buf-list (identity ;;used to be reverse                                                                         
                           (sort
                            (my-filter (lambda (x) (string-match "^\\*shell\\*" (buffer-name x))) (buffer-list))
                            '(lambda (a b) (string< (buffer-name a) (buffer-name b)))))))
      (setq next-shell-buffer
            (if (string-match "^\\*shell\\*" (buffer-name buffer))
                (get-buffer (cadr (member (buffer-name) (mapcar (function buffer-name) (append shell-buf-list shell-buf-list)))))
              nil))
      (setq buffer
            (if create
                (generate-new-buffer-name "*shell*")
              next-shell-buffer))
      (shell buffer)))

Another take on multiple shells, one shell per tramp host. If you already have a shell for that user@host then raise it.

 (defun my-shell (&optional buffer)
   (interactive)
   (let* ((tramp-path (when (tramp-tramp-file-p default-directory)
                        (tramp-dissect-file-name default-directory)))
          (host (tramp-file-name-real-host tramp-path))
          (user (if (tramp-file-name-user tramp-path)
                  (format "%s@" (tramp-file-name-user tramp-path)) ""))
          (new-buffer-name (format "*shell:%s%s*" user host)))
     (shell (if host new-buffer-name buffer))))

Garbage output from ls and gcc

Take a look at AnsiColor.

Completions

By default, tap-completion in shell-mode can complete commands and files, but there is no support for context-sensitive completion. The following modules extend tap-completion:

Backgrounding a process

You might find it difficult to background a process that’s started, once you’re in shell mode.

If you hit ‘C-z’, you end up backgrounding Emacs!

To solve this, just execute

 M-x local-set-key RET C-z self-insert-command

Now ‘C-z’ actually transmits to the shell.

And if you want to background Emacs, just go to a different buffer.

‘C-q C-z’ doesn’t work? - No, but C-c C-z should.

Remote sessions with SSH and completion with Tramp

Inside the a *shell* buffer I often SSH to other machines. It’s the nature of one’s work. Anyway, you lose completion. You can partially get it back by running `M-x cd /$HOSTNAME:$PWD’ where $HOSTNAME is the host you’ve SSH’d to, and $PWD is your current working directory on the machine. This requires TrampMode. Unfortunately, completiong for root-relative paths doesn’t work, since the root for Tramp doesn’t translate to the root of a file system – (not (equal "/host:/" "/")). Really handy otherwise.

A. I feel your pain. Doesn’t work, would be nice if it did: SubprocessCompletion

Any new shell created when the current buffer is visiting a remote file/dir will automatically ssh to the remote default-directory for that file, however if you try this a second time in any other remote file/dir, it hangs. The way around it is to just create a local shell and ssh, but it would be nice to not have to do this.

Tracking the current working directory of the shell

The built-in mechanism for keeping Emacs apprised of the shell’s current directory is not very reliable, and can be thrown off by any command which it doesn’t recognize as a directory-changing command (i.e., shell aliases).

Here are alternative methods that track the cwd, regardless of what command is being used to set it: ShellDirtrackByPrompt ShellDirtrackByProcfs

I can’t get dir tracking to work correctly. Either the regex isn’t catching the prompt, or the prompt doesn’t get read at the correct time. Either way, it doesn’t work. Can someone point me to what I’m doing wrong?

My bash shell prompt is defined this way in .bashrc:

    export PS1='\h:\w\n> '

…which looks like this in practice:

    tnsfc64:~/elisp
    > 

I use this dir tracking code in my .emacs file:

    (defun my-current-directory (text)
      (if (string-match "\\w*:\\([^\n]+\\)\n> " text)
          (setq cur-dir (substring text (match-beginning 1) (match-end 1)))
        (cd cur-dir)
        (message "dir tracking %s" cur-dir)))
    (defun my-shell-setup ()
      "Track current directory"
      (add-hook 'comint-output-filter-functions 'my-current-directory nil t))
    (setq shell-mode-hook 'my-shell-setup)

Thanks, -Tennis

Show the current directory in the mode-line

Restore some sanity to your PS1 by putting the full working directory in the mode-line: ModeLineDirtrack

Icicles Enhancements to Shell Mode

You can use Icicles completion in Shell mode. Whenever there are multiple completion candidates, Icicles completion is used (if Icicle minor mode is on). This means you can cycle to choose a candidate, complete using one or more substrings or regexps (progressive completion), and so on. See Icicles - Completion in Comint Modes.

You can also use `C-`’ to quickly find, reuse, and edit a previous shell input, matching it in several ways. See Icicles - Reuse Shell Inputs.

Clearing Shell Mode Output

Use this command to clear the shell buffer:

 (defun clear-shell ()
   (interactive)
   (let ((comint-buffer-maximum-size 0))
     (comint-truncate-buffer)))

You can also just use M-x erase-buffer.

Switch between Term-mode and Shell-mode

Below is a function which allows you to switch between Term mode and Shell mode, in the same buffer.

Notice that it works properly only if started from an term buffer (started with ‘ansi-term’) which properly initializes bash for working in a terminal.

 (require 'shell)
 (require 'term)
 (defun term-switch-to-shell-mode ()
  (interactive)
  (if (equal major-mode 'term-mode)
      (progn
        (shell-mode)
        (set-process-filter  (get-buffer-process (current-buffer)) 'comint-output-filter )
        (local-set-key (kbd "C-j") 'term-switch-to-shell-mode)
        (compilation-shell-minor-mode 1)
        (comint-send-input)
      )
    (progn
        (compilation-shell-minor-mode -1)
        (font-lock-mode -1)
        (set-process-filter  (get-buffer-process (current-buffer)) 'term-emulate-terminal)
        (term-mode)
        (term-char-mode)
        (term-send-raw-string (kbd "C-l"))
        )))

I bound it to C-j to easily switch between the two modes:

  (define-key term-raw-map (kbd "C-j") 'term-switch-to-shell-mode)

[Question] Why not simply shifting between character mode and line mode? Is there a bigger reason to really shift to a real Shell buffer?

Piping shell output into an Emacs buffer

Remember that Emacs has native built-in commands of M-! (or “M-x shell-command”) and M-| (or “M-x shell-command-on-region”), each of which allows a one-line command in the mini-buffer, and returns the output to the mini-buffer (if the output is one line, like the results of `date`) or to a new buffer, if the shell output is more than one line.

Also, prefixing either command with Ctrl-U will send the output to the active editing buffer, rather than sending it to a separate buffer. Suppose you have a marked block to change (by an external command like `sort` or `sed` or `awk`). Use M-| to see the output in a new window, and if satisfied, use Ctrl-U M-| to change the marked block in the current window. If not satisfied, just run M-| again with different parameters or option switches, and this will overwrite the output of the new window, without destroying the contents of the currently active window.


CategoryExternalUtilities CategoryShell