Emacs Lisp: Walk Directory, List File Names

By Xah Lee. Date: . Last updated: .

Here's how to walk directory.

List Directory (No Subdir)

(directory-files DIRECTORY &optional FULL MATCH NOSORT COUNT)
Return a list of file paths in DIRECTORY. (No Subdir)
  • If FULL is non-nil, return absolute file names.
  • If MATCH is non-nil, should be a Regular Expression. Only return matched files.
  • If NOSORT is non-nil, the list is not sorted, order is unpredictable.
  • If COUNT is non-nil, it should be a integer n, return max of n paths.

Warning: the returned path may include the unix dot . (means current dir) and dot dot .. (means parent dir). To exclude them, use the MATCH param.

;; walk dir, top level only

 (lambda (x) (insert x "\n"))
  "c:/Users/xah/web/xahlee_info/emacs/emacs/i/" nil "\.jpg$" t))

;; sample output

;; xah_talk_show_2019-02-10_p6c54.jpg
;; xah-fly-keys_kinesis_2017-09_60363.jpg
;; unicode_books_37530-s1155x866.jpg
;; todo_list_crossout_nothing.jpg
;; the_book_of_shen_lang.jpg

List Directory and All Subdir

Return list of all files under directory DIR whose names match REGEXP. (Warning: the match is done against file name only, not full path.)

This function works recursively. Files are returned in “depth first” order, and files from each directory are sorted in alphabetical order.

  • Returned list elements are full paths.
  • Optional argument INCLUDE-DIRECTORIES non-nil means also include in the output directories whose names match REGEXP.
;; walk dir and all subdir

 (lambda (x) (insert x "\n"))
 (directory-files-recursively "~/web/xahlee_info/emacs/emacs/" "\.png$"))

;; sample output

;; ~/web/xahlee_info/emacs/emacs/i/menu/emacs_goto_menu.png
;; ~/web/xahlee_info/emacs/emacs/i/menu/emacs_help_menu.png
;; ~/web/xahlee_info/emacs/emacs/i/menu/emacs_search_menus.png
;; ~/web/xahlee_info/emacs/emacs/i/menu/emcs_options_menu.png
;; ~/web/xahlee_info/emacs/emacs/i/menu/emcs_tools_menu.png
;; ~/web/xahlee_info/emacs/emacs/i/unicode/Carbon_emacs_22_unicode.png

Filter by Dir Depth Level

;; 2021-10-14 example of filter a dir by depth range

(require 'seq)

(setq $xrootDir "~/web/ergoemacs_org/")
(setq $xdirLevelMin 3)
(setq $xdirLevelMax 3)

(defun xah-find-count-slash (Path)
  "Count the number of slash in path.
Useful for finding the level of a nested dir.
Note: you should probably call `expand-file-name' on Path first to canonize path, to make sure dir name always ends in slash.
Version 2021-10-11"
  (seq-count (lambda (x) (char-equal x ?/)) Path))

(setq $xrootDirDepth (xah-find-count-slash (expand-file-name $xrootDir)))

(setq $result
         (lambda (x)
           (let (($df (- (xah-find-count-slash x) $xrootDirDepth)))
             (and (>= $df $xdirLevelMin) (<= $df $xdirLevelMax))))
         (directory-files-recursively $xrootDir ".")))

(mapc (lambda (x) (print x)) $result)

Skipping Subdir

In other programing languages (perl python golang), usually the dir walker lets you skip some specified directory. The walker calls a doFile function you write, and pass current dir or file, so you can skip it to prevent going into.

In elisp, there's a package find-lisp.el that lets you use a regex to filter dir, but is very slow. I do not recommend it. [Emacs Lisp: find-lisp.el]

To skip some subdir, it's faster if you just use directory-files-recursively then filter result.


 (lambda (path)
   (not (seq-some
         (lambda (x) (string-match x path))
         skipDirs )))
 (directory-files-recursively "/Users/xah/web/xahlee_info/" "\\.svg$" ))

seq-filter and seq-some are in emacs 25.

[see Emacs Lisp: Sequence Functions]

Emacs Lisp File/Buffer

Practical Elisp ⭐

Writing Command

Text Processing

Get User Input


Writing Script