Emacs: Open a shell in the current directory

One of the thing I often need is a shell in the same directory as a file I’m editing. Emacs doesn’t have a quick way to do this, so I hacked one together.

(defun shell-here ()
  "Open a shell in `default-directory'."
  (interactive)
  (let ((dir (expand-file-name default-directory))
        (buf (or (get-buffer "*shell*") (shell))))
    (goto-char (point-max))
    (if (not (string= (buffer-name) "*shell*"))
        (switch-to-buffer-other-window buf))
    (message list-buffers-directory)
    (if (not (string= (expand-file-name list-buffers-directory) dir))
        (progn (comint-send-string (get-buffer-process buf)
                                   (concat "cd \"" dir "\"\r"))
               (setq list-buffers-directory dir)))))

I have this bound to C-c !, which is an open global binding. It’s working well for me, though there are some things I’d like to see improved, like the buffer-name comparison used to switch to the shell buffer. It would also be nice if you could specify the directory if you call it with a prefix.

2008/07/29

Discussion

M-x eshell from within a buffer opens a shell for me in the file’s directory. As does M-x shell. I thought maybe Carbon Emacs had a hack or something, so I tried /usr/bin/emacs in Leopard and it worked too. This also worked on a RHEL box. The only thing these all have in common is that they’re using Emacs 22+, any chance you’re using 21?

Andrew
2008/07/30

That certainly works, but only if you don’t already have a shell open. If you have a shell currently open, my function switches to it and changes to `default-directory’.

If you already have *shell* and run M-x shell again, it merely switches to that buffer, it doesn’t point it at `default-directory’.

Ian
2008/07/30

Ahh, ok. I just misunderstood what it was achieving. Sorry for that.

Andrew
2008/07/30

You can C-u M-x shell to get a new shell even if one already exists. Not as easy to type as C-c !, but easily mapped.

Wayne
2008/07/30

@Wayne, That doesn’t do what I want, which is to reuse an existing shell buffer so I can leverage the history and scrollback. You also have to hit RET a second time when it prompts for a buffer name.

Ian
2008/07/30

On Win32 it invokes cmd shell. Can you please suggest what changes will be required to invoke/reuse an eshell?

Manish
2008/07/30

Good tip! I’ve been using C-u M-x eshell over here, but it would be nice to be able to reuse history. =) Thanks for sharing!

Sacha Chua
2008/07/31

@Manish, If you replace “*shell*” with “*eshell*” and (shell) with (eshell), it should work.

Ian
2008/07/31

I have been using multiple shells for over 6 years and retain the shell history for all of them. It is great for going back to a project months/years later and wondering “now what was the exact command line that i needed to type”.

I should update the page http://www.emacswiki.org/cgi-bin/wiki/UsingMultipleShells with something newer.

Peter
2008/07/31

Note that this needs patching to work correctly with Emacs running on Windows if you’re still having it shell to cmd.exe and not e.g. bash under cygwin, for 2 reasons:

* backslash path delimiters
* linefeed characters (\r vs. \r\n)

to fix this, replace the concat line:

(concat “cd \”" dir “\”\r”))

with:

(concat “cd \”" (replace-regexp-in-string “/” “\\” dir t t) “\”\r\n”))

Daren
2008/08/06

Participate