For years I've been using a zsh script that causes a pushd to implicitly happen everytime you change directories. The script also sets up 'b' and 'f' aliases, short for backwards and forwards, that move you up and down the stack, similar to the back and forward buttons in a web browser. Example session:

/etc $ cd /tmp
/tmp $ cd /bin
/bin $ b
/tmp $ b
/etc $ f
/tmp $ f
/bin $

I've found it incredibly useful and I was wondering, what's the best way to set this up in eshell?

Edit: See the code I went with here, slight modification of below: https://gist.github.com/jgarvin/0627ed76a773ade222f6

1 Answer 1


The following saves cd history and provides eshell commands b and f to navigate that history:

;;*--- track cd history ------------------------------------------------*/
(defvar-local eshell-hist-dirs nil)

(add-hook 'eshell-directory-change-hook
          (defun eshell-update-hist-dir ()
            (push (eshell/pwd) eshell-hist-dirs)
            (setq eshell-hist-index 0)))

;;*--- navigate history ------------------------------------------------*/
(defvar-local eshell-hist-index 0)

(defun eshell-forward (n)
  (unless eshell-hist-dirs
    (user-error "eshell-hist-dirs is empty, cd a few times"))
  (let ((dirs eshell-hist-dirs)
        (index (+ eshell-hist-index n)))
    (prog1 (eshell/cd (nth index dirs))
      (setq eshell-hist-dirs dirs
            eshell-hist-index index))))

(defun eshell/b ()
  (eshell-forward 1))

(defun eshell/f ()
  (eshell-forward -1))

BTW, eshell's built-in cd command already provides several ways to jump to history directories, for example, cd - for the last directory, cd -1 for the penultimate directory and cd =tmp for the last directory which contains tmp. See (eshell) Built-ins for more information.

  • This works great! Only caveat I have is that if you do 'b' over and over passed the end of the stack, it will push the last directory onto the stack over and over. So if you do 'b' over and over again until it stops going backward, then press it 4 more times, you will have to do 'f' 4 times before it actually starts going forward in the dir history again. Maybe just needs a check to make sure in the directory change hook that it actually changed? Commented Nov 4, 2015 at 18:01
  • Oop, I might need to reset eshell-hist-index to zero once user runs cd from eshell.
    – xuchunyang
    Commented Nov 4, 2015 at 18:10
  • One other suggestion, wouldn't it be better to use defvar-local? Otherwise I think you're sharing the same cd history across all eshells which I think would be pretty surprising behavior. Commented Nov 4, 2015 at 18:39
  • Yes, using buffer-local variables here is correct and I will do that, currently using setq is for ease of development (because I'm wriing these in *scratch* buffer and I need to examine their values frequently).
    – xuchunyang
    Commented Nov 4, 2015 at 18:46
  • Here's my attempt: gist.github.com/jgarvin/0627ed76a773ade222f6 . I changed it to use defvar-local and made it so the starting directory is put in the history. Commented Nov 4, 2015 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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