2

Is it possible from within Emacs to find directories with a given depth from the current directory from within Emacs and receive their respective location in form of a list? I want it to work cross platform...

1

I'd be inclined to use find for that:

(let ((dirname (expand-file-name "~/"))
      (depth 3))
  (split-string
   (shell-command-to-string
    (format "find %s -mindepth %d -maxdepth %d -type d -print0 2>/dev/null"
            (shell-quote-argument dirname) depth depth))
   "\0" :omit-nulls))

n.b. -mindepth, -maxdepth, and print0 are not POSIX options, so YMMV regarding portability.

  • I know but find would not work across different platforms. – sidharth arya Oct 23 '18 at 9:54
  • @sidhartharya You didn't mention the requirement that the code should work across platforms in your question. Therefore, this answer is equally valid as the others. (That's why I up-voted it.) Furthermore, the gnu-find tool is available for several platforms. E.g., on Windows by mingw. – Tobias Oct 24 '18 at 9:43
  • Yes gnu find is available across platforms but I want to do it , in a way, so the user doesn't have to explicitely install something specifically for that.. And also if i had to issue a shell command why would i ask it here. But thank's i will make the edit – sidharth arya Oct 24 '18 at 9:51
1

The elgrep-search command has options :mindepth and :maxdepth. Elgrep is available via package-install from the melpa package archive (instructions how to add melpa to package-archives can be found on the melpa "Getting Started" page).

You can use elgrep as follows to get a list of matching file names of a specific depth. In the example I search in my HOME-directory (~/) for files matching \.el\' without in-file matches (that's the nil) with minimal and maximal recursion depth 2.

(require 'elgrep)
(mapcar 'car (elgrep-search "~/" "\\.el\\'" nil :recursive t :mindepth 2 :maxdepth 2))

Elgrep actually returns filematches. That are conses of the file name and a list of in-file matches. In our case the list of in-file matches is empty since we passed nil for the in-file regexp. Because of that structure you need the (mapcar 'car ...). See the documentation of the elgrep-search command for further details.

Note, that mindepth and maxdepth are also available via the gui-version elgrep-menu. There you can let elgrep search asynchronously. That way it does not block your Emacs.

1

Library find-dired+.el can help with this. C-h f find-dired:

find-dired is an interactive compiled Lisp function in find-dired+.el.

(find-dired DIR ARGS &optional DEPTH-LIMITS EXCLUDED-PATHS)

Run find and put its output in a buffer in Dired Mode.

Then run find-dired-hook and dired-after-readin-hook.

The find’ command run (after changing intoDIR) is essentially this, whereLS-SWITCHESis(car find-ls-option)`:

 find . \( ARGS \) LS-SWITCHES

Optional args:

  • DEPTH-LIMITS: Minimum and maximum depths: (MIN-DEPTH MAX-DEPTH).
  • EXCLUDED-PATHS: Strings matching paths to be excluded. Uses find switch -path.

When both optional args are non-nil, the find command run is this:

find . -mindepth MIN-DEPTH -maxdepth MAX-DEPTH
     \( -path EXCLUDE1 -o -path EXCLUDE2 ... \)
     -prune -o \( ARGS \) LS-SWITCHES

where EXCLUDE1, EXCLUDE2... are the EXCLUDED-PATHS, but shell-quoted.

Same thing for the related commands: find-name-dired, find-grep-dired, and find-time-dired - they all take arg DEPTH-LIMITS.


To reply to @Tobias's comment: Yes, find-dired+.el (which extends standard library find-dired.el) depends on a UNIX or GNU/Linux find command. On MS Windows you can use Cygwin or any other porting of the command to Windows.

  • As I understand the code find-dired+.el uses the external find program. Therefore, the same comments as for Phils answer apply. Disclaimer: I had only a short glance on the code. It may be that you have some fallback there that uses emacs-internals when gnu-find is not available. I didn't check for that. Please correct me if that is the case. – Tobias Oct 24 '18 at 9:46
1

You can use the ls command of the built-in eshell for listing the files with some predefined depth.

You have to specify the depth by the right number of concatenated file name generator expressions */.

Example:

(split-string
 (substring-no-properties
  (eshell-command-result "ls /usr/share/emacs/26.1/*/*/*/*/*/*(.)")
  )
 "\n" t)

The appended modifier (.) says that the generator only expands regular file paths.

Note that the backend eshell-do-ls command is a pure Emacs Lisp implementation of the ls command. Yet in this case the actual work is not done by ls but by eshell-glob.

If you also want to list directories you should add the -d switch to the ls command. Otherwise the files contained in the directories would also be listed:

(split-string
 (substring-no-properties
  (eshell-command-result "ls -d /usr/share/emacs/26.1/*/*/*/*/*/*")
  )
 "\n" t)

If you actually don't want any special features of ls you can also use pure eshell-extended-glob:

(eshell-extended-glob "/usr/share/emacs/26.1/*/*/*/*/*/*")

If you want to list all files with some minimal depths you can expand with the two-star form **, e.g.,

(eshell-extended-glob "/usr/share/emacs/26.1/*/*/*/**/*")
  • That's a great idea . Thank you so much. – sidharth arya Oct 25 '18 at 2:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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