19

Is there a way, possibly using a package, to recursively list all the files (with paths) and sub-directories (or at least the empty sub-directories, since the paths to the non-empty ones can be gleaned from the paths of the files contained therein) of the current directory?

The closest I could find is the projectile-find-file function of the projectile package (alternatively, the helm-projectile-find-file function of the helm-projectile package), but it doesn't seem to be able to list empty folders. Additionally, it seems to work only with Git and other version control repositories, but there may be a workaround for this limitation.

9
  • 2
    'm not quite shure what you try to do, but [this blog post](www.turingmachine.org/bl/2013-05-29-recursively-listing-directories-in-elisp.html) might contain what you need, or you may try [this one](ergoemacs.org/emacs/elisp_traverse_dir.html) as a starter.
    – theldoria
    Commented Jun 6, 2017 at 9:46
  • 1
    What do you mean by "list"? Do you want an Emacs Lisp functions that return a list of strings with the paths? Do you want a buffer with the paths in it, say, one per line? Do you want a dired buffer with all the files? (That last one is easy, add "-R" to the ls switches in dired.)
    – Omar
    Commented Jun 6, 2017 at 16:17
  • See also Find relative filenames recursively in Emacs Commented Jun 6, 2017 at 19:00
  • @Omar: I have to ideal requirements: (1) that it will be either part of Emacs or part of a package, (2) that it will work with either helm or ivy, i.e. that the results will be displayed in a helm or ivy buffer. If it is impossible to satisfy both requirements, the 2nd one is more important for me.
    – Evan Aad
    Commented Jun 7, 2017 at 6:48
  • 1
    That's really two different questions. But OK, I provided an answer for each.
    – Drew
    Commented Jun 10, 2017 at 22:30

9 Answers 9

11

Assuming you use ivy you can use this function

    (defun fhd/counsel-everything ()
      "list everything recursively"
      (interactive)
      (let* ((cands (split-string
                     (shell-command-to-string "find .") "\n" t)))
        (ivy-read "File: " cands
                  :action #'find-file
                  :caller 'fhd/counsel-everything)))
2
  • Thanks. What if I use helm?
    – Evan Aad
    Commented Jun 6, 2017 at 10:20
  • 1
    Sorry, I don't know about helm. ivy is pretty lightweight. Give it shot.
    – fhdhsni
    Commented Jun 6, 2017 at 10:26
23

directory-files-recursively

(I think this was added in Emacs 25)

here's the link to the manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/Contents-of-Directories.html

Return all files under directory whose names match regexp. This function searches the specified directory and its sub-directories, recursively, for files whose basenames (i.e., without the leading directories) match the specified regexp, and returns a list of the absolute file names of the matching files (see absolute file names). The file names are returned in depth-first order, meaning that files in some sub-directory are returned before the files in its parent directory. In addition, matching files found in each subdirectory are sorted alphabetically by their basenames. By default, directories whose names match regexp are omitted from the list, but if the optional argument include-directories is non-nil, they are included.

Example

(directory-files-recursively default-directory "")
3
  • It doesn't find empty directories
    – fhdhsni
    Commented Jun 6, 2017 at 12:57
  • 1
    @fhdhsni did you try setting include-directories to t? I'm at work on Emacs 24, and cannot try this right now, but I can test this at home in few hours.
    – wvxvw
    Commented Jun 6, 2017 at 13:00
  • My bad. I didn't do that. You may want to include it in your answer.
    – fhdhsni
    Commented Jun 6, 2017 at 13:09
6

This answer assumes that you want to display a listing of the file and dir names, instead of obtaining a Lisp list of them.

Use standard Emacs commands find-dired , find-name-dired, or find-grep-dired. The found file and dir names are displayed in a Dired-mode buffer. (You can put all the power of Dired to work on the results.)

If you use library find-dired+.el then you have enhanced versions of those standard Emacs commands, plush you have a command find-time-dired, which find files that are newer or older than a given timestamp.

2
  • 2
    find-dired is exactly what I'm looking for, but is there a way to print only names? Because otherwise single filename takes multiple lines for no reason as I absolutely don't care of size, date, or permissions of files. I've tried running (setcar find-ls-option "-printf '%p\n'") prior to find-dired, but for some reason this way dired don't want to open a file upon pressing Enter over an item.
    – Hi-Angel
    Commented Oct 23, 2017 at 20:01
  • 3
    @Hi-Angel: The buffer that the results are displayed in is in Dired mode. So you can just hit ( to toggle showing more than the file names on/off. I leave it off most of the time (no details shown), and just toggle it on briefly when I want to check some details.
    – Drew
    Commented Oct 24, 2017 at 1:37
2

This answer assumes that you want to obtain a Lisp list of the file and dir names, instead of displaying a listing of them.

If you use library Dired+ then you can use function diredp-files-within. (You need not be in a Dired buffer to use it.)

This works with any Emacs version, and it is more general than directory-files-recursively.

  • You can pass it a list of files and dirs, and it acts recursively in each of them.

  • Or you can pass it a function that returns such a list.

    • If there is a Dired buffer for a directory that gets processed then the function is invoked in that buffer to return the list of files to include.

      For example, if the function is dired-get-marked-files then only the marked files and subdirectories are included.

  • You can pass it a predicate that each each file or directory must satisfy. Regexp matching is of course one kind of predicate.

  • You can tell it not to follow symbolic links.

1

See https://github.com/technomancy/find-file-in-project

There are commands to either find file or find directories. But not both.

If you just want to list all sub-directories and files recursively in one buffer, there are two commands built in Emacs for ages:

  1. M-x find-dired. It's dependent on CLI tool find. At Windows, you need install Cygwin or MYSYS which has find

  2. M-x find-lisp-find-dired. Same as find-dired but written in Lisp. So there is no third party dependency. Besides, it can recognize locale out of box. But it's slower than find-dired

3
  • My use case would be the same as anyone who uses the UNIX shell command ls, or the Emacs function find-file, both of which list both files and directories, including empty directories.
    – Evan Aad
    Commented Jun 6, 2017 at 11:00
  • Are find-dired and find-lisp-find-dired recursive in that they list not only the contents of the current directory, but also the contents of each of its sub-directories, sub-sub-directories, etc.?
    – Evan Aad
    Commented Jun 6, 2017 at 19:06
  • Yes, recursively
    – chen bin
    Commented Jun 7, 2017 at 0:33
1

My answer is similar to using find-dired:

(shell-command (concat "find " my-directory " -name foo.txt"))

Then, switch to buffer *Shell Command Output*, and you'll have a buffer with a list of files, and/or directories, one per line.

0

This is independent of Emacs, but if all you want to do is list all files and sub-directories As in you don't require any hyperlinks to go to the file in Emacs, but simply want to list the directories, files, and subdirectories in an Emacs buffer, you can simply use the shell command ls -R > nameOfFile.txt. And then open the resulting file in Emacs.

You can, of course, run this within eshell M-x eshell to the same effect, if you are on Windows and don't have an ls command.

This command will revert the output of ls -R to the specified file name. I usually like to name it the name of the directory. ls -R is the command to recursively run ls. This will include directories and sub-directories that have no files in them.

I like to use this command to compare the contents of directory structures within Emacs quite often. Simply run the command on two different directories, open the resulting files in two different Emacs buffers and run M-x compare-windows to compare the two.

0

To get all files and sub-directories in Emacs:

C-u 2 ESC x dired RET R

That is, type C-u 2, then M-x, then d i r e d, then RET.

The value of dired-listing-switches appears in the minibuffer. Type R, to append R to those ls switches (e.g., change -al to -alR). When you hit RET those switches take effect. Switch R lists subdirs, recursively.

0
-2
(defun my-dir-list (source)
  ;;
  ;; Print list files in current buffer
  ;;
  ;; Not tested, system-type: gnu
  ;; Tested,     system-type: windows-nt
  ;;
  (interactive "sDirectory: ")
  (let ((n 0)
    (l-file-dir (and (cd source) (directory-files-and-attributes "./")))
    (dir-list '())
    (file-list '())
    )
    (princ (format "%s\n" default-directory) (current-buffer))
    (while l-file-dir
      (if (nth 1 (car l-file-dir))
      (setq n (1+ n)
        dir-list (cons ((lambda (source)
                  (and (not (string-prefix-p "." (car source))) source))
                (car l-file-dir)) dir-list)
        )
    (princ (format "%s\n" (concat default-directory
                      (and (string-match "\\.[0-9|A-z]" (caar l-file-dir))
                       (caar l-file-dir)))) (current-buffer))
    )
      (setq l-file-dir (cdr l-file-dir))
      )
    (while (caar dir-list)
      (setq dir-list (cdr dir-list))
      (cd "..")
      )
    )
  'ok
  )

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.