Emacs Lisp: Walk Directory, List File Names
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 (mapc (lambda (x) (insert x "\n")) (directory-files "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
(directory-files-recursively DIR REGEXP &optional INCLUDE-DIRECTORIES PREDICATE FOLLOW-SYMLINKS)
-
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 (mapc (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" (interactive) (seq-count (lambda (x) (char-equal x ?/)) Path)) (setq $xrootDirDepth (xah-find-count-slash (expand-file-name $xrootDir))) (setq $result (seq-filter (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.
(setq skipDirs [ "ergoemacs_org/emacs_manual/" "xahlee_info/REC-SVG11-20110816/" "xahlee_info/clojure-doc-1.8/" ]) (seq-filter (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.