17

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.

Drew
  • 75,699
  • 9
  • 109
  • 225
Evan Aad
  • 1,461
  • 1
  • 14
  • 29
  • 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 Jun 06 '17 at 09:46
  • 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 Jun 06 '17 at 16:17
  • See also [Find relative filenames recursively in Emacs](https://codereview.stackexchange.com/q/79439/33560) – Håkon Hægland Jun 06 '17 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 Jun 07 '17 at 06:48
  • Saying "*list all the files...and directories*" is a bit ambiguous. Do you want to obtain a Lisp *list* of the files and dirs? Or do you want to see a displayed listing of them? – Drew Jun 09 '17 at 22:19
  • @Drew: Ideally I'm looking for a list that displays in a `helm` or `ivy` buffer. – Evan Aad Jun 10 '17 at 03:10
  • What does that mean: "*a list that displays...*"? Are you looking for code that displays a list or are you looking for a Lisp list (which you can display wherever you like, including using Helm or Ivy)? – Drew Jun 10 '17 at 14:47
  • @Drew: Let's say I'm interested in both alternatives. – Evan Aad Jun 10 '17 at 15:05
  • 1
    That's really two different questions. But OK, I provided an answer for each. – Drew Jun 10 '17 at 22:30

8 Answers8

20

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 "")
Basil
  • 12,019
  • 43
  • 69
wvxvw
  • 11,222
  • 2
  • 30
  • 55
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)))
fhdhsni
  • 693
  • 6
  • 16
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.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • 1
    `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 Oct 23 '17 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 Oct 24 '17 at 01: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.

Drew
  • 75,699
  • 9
  • 109
  • 225
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

chen bin
  • 4,781
  • 18
  • 36
  • 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 Jun 06 '17 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 Jun 06 '17 at 19:06
  • Yes, recursively – chen bin Jun 07 '17 at 00: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.

Drew
  • 75,699
  • 9
  • 109
  • 225
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.

-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
  )
joe
  • 27
  • 2