2

I want to go to a specific directory after I start a shell. So I put these lines in my .emacs file:

(shell)
(shell-command "cd C:/MyStartUp/ThisDirectory")
(setq default-directory "C:/MyStartUp/ThisDirectory")

However, whenever I start emacs, the shell ends up in this directory c:\emacs-26.3\bin> How do I fix this?

2

First

(shell)

opens a *shell* buffer and starts a shell process in it. Then

(shell-command "cd C:/MyStartUp/ThisDirectory")

runs a non-interactive shell which executes the command cd C:/MyStartUp/ThisDirectory and exits. Then

(setq default-directory "C:/MyStartUp/ThisDirectory")

sets the current directory of the buffer where the shell process is running. This does not affect the running process.

You need to either set the current directory of the *shell* buffer before starting the shell process, or send the cd command to the running shell. Setting the current directory of the *shell* process is a little complicated because the way to do it depends on whether the *shell* buffer already exists. You also need to decide whether you want to change the current directory if a shell is already running, which sending the cd command will always do.

To set the current directory if a new *shell* buffer is created:

(let ((default-directory "C:/MyStartUp/ThisDirectory"))
  (shell))

To set the current directory of an existing *shell* buffer if there is one:

(let ((buffer (get-buffer "*shell*")))
  (if buffer
    (with-current-buffer buffer
      (shell-cd "C:/MyStartUp/ThisDirectory"))))

shell-cd runs the cd function, which is a bit fancier than directly setting default-directory: it honors CDPATH (which you may or may not care about). shell-cd also takes care to update the directory shown in buffer lists. You can run this before the previous snippet to cover both the case where no *shell* buffer exists and the case where a *shell* buffer exists without a running shell process. Note that this does not cover the case of an existing *shell* buffer with a running shell process.

To change the directory of the running shell, send a cd command to it. (cd works for all common shells including Unix-like *sh, fish, Windows cmd and Plan 9 rc, but if you use a more exotic shell you'll need to use its own syntax.) This doesn't work if you want to change to a remote directory using Tramp: for that, you have to decide on the host before running the shell.

(shell)
(with-current-buffer "*shell*"
  (shell-cd "C:/MyStartUp/ThisDirectory")
  (let ((cmd (concat "cd " (shell-quote-argument default-directory) "\n")))
    (comint-send-string nil cmd))

Note that this snippet assumes that your shell accepts the same quoting mechanism as your platform's default shell. Otherwise you may need to replace shell-quote-argument with a function that's suitable for your shell's syntax.

Sending input to the shell assumes that the shell is listening to input. If the shell is running an interactive application, that application will receive the input. There's no easy way to detect that and no reliable way to work around it.

1

In some circumstances, having the trailing forward slash for the default-directory is necessary. My recollection is that this may depend upon the OS. It is possible to pass commands to the shell buffer under-the-hood with comint-send-string and comint-send-input, but that appears to be unnecessary in this particular use-case. The beginning directory in the shell buffer will be inherited from the default-directory, which can be let-bound:

(let ((default-directory "C:/MyStartUp/ThisDirectory/"))
  (shell))
3
  • I did have the / in the end in my case, I forgot to add that when I posted here. After I used your command, my starting directory becomes c:\> but never goes to the default-directory. Although my M-x find-file does start to look for files in that default-directory.
    – tony
    Jul 29 '20 at 16:20
  • I just fired up my Windows version of Emacs and tested the code ... it works correctly "as-is" -- both with a trailing forward slash and also without a trailing forward slash. I would suggest starting Emacs with no configuration (e.g., Emacs -q) and then evaluate the code above, either in a *scratch* buffer or just by typing M-x eval-expression aka M-: Perhaps there is a typo in your path or something in your config that is causing problems.
    – lawlist
    Jul 29 '20 at 18:25
  • I found out what my problem was. The name ThisDirectory I used as an example actually contains space and - like OneDrive - ThisDirectory. So I incorrectly used \ for the space and other characters. It turns out not only it's not needed, it confused this shell command to go to the correct path. Thanks all for the help.
    – tony
    Jul 30 '20 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.