15

Generally speaking, I would like to be able to open all files within a given set of directories (and their subdirectories) where the filename matches a given regexp.

For example

  /home/nispio/project:
  total used in directory 1612 available 1000000000
  drwxrwxr-x 13 nispio group    4096 Sep 19 14:06 .
  drwxrwxr-x  7 nispio group    4096 Sep 22 16:41 ..
  drwxrwxr-x  2 nispio group    4096 Sep 19 12:46 cfg
  drwxrwxr-x  2 nispio group    4096 Sep 19 12:46 hlp
* drwxrwxr-x  2 nispio group    4096 Sep 23 16:52 hst
* drwxrwxr-x  2 nispio group    4096 Sep 29 14:52 inc
* drwxrwxr-x  2 nispio group    4096 Oct  1 12:53 lib
  drwxrwxr-x  2 nispio group    4096 Sep 19 12:46 mcr
  drwxrwxr-x  2 nispio group    4096 Sep 24 10:50 pyl
  drwxrwxr-x  2 nispio group    4096 Sep 19 12:46 snr
  drwxrwxr-x  2 nispio group    4096 Sep 19 12:46 unix

I have marked the directories hst, inc, and lib, and now I want to visit all files with extensions .c, .cc, and .h within those three directories and their subdirectories.

It would be even better if I could see everything that I am opening before I open it. If the dired buffer was updated to show me all of the files that matched my search, and all of those were highlighted, I could do a sanity check to make sure that my search returned what I expected.

I am open to suggestions to do this same thing using helm or dired+ or any other extensions that will let me navigate my filesystem more easily.

1
  • Has Mathias or Drew answered your questoin? Or were you looking for something different?
    – Malabarba
    Oct 15, 2014 at 12:54

4 Answers 4

18

Try this:

C-u C-x d

This let's you enter arguments for how Dired should list files. By default it says -al at the prompt. Add R to that, ending up with -alR. Type RET.

Select/type a directory and then press RET.

This will recursively open all directories from the one you select, and below.

From here, type % m to mark all files matching a certain file name pattern. I also often then type t and then k to kill (hide) all files I am not interested in. Type t again to mark all files.

As far as actually opening the files, I don't think there is a standard way to do it, but you can easily define a new command to do it (place it in your .emacs file):

(defun dired-find-marked-files ()
 (interactive)
 (dolist (f (dired-get-marked-files)) 
  (find-file f)))

Most probably someone has already included this in some nice Dired enhancement package, but it's fun to do it yourself too ;)

Enjoy!

1
  • Big thanks, -alR and %r was what I was looking for to bulk rename script files when refactoring. Have a marvelous day. :D Apr 1, 2022 at 14:05
8

You can do this easily with helm-projectile-find-file. Since Projectile keeps track of every files with its relative path, you can easily narrow down to anything. Let's use your example. In your case, you want to open files in hst, inc, and lib. You can retrieves all files belongs to this directory by two ways:

  • In Helm prompt of helm-projectile-find-file, enter each directory and marked files narrowed to that directory. For example, first I enter ^hst/ (which narrows to all files that contains hst/ at the beginning of each candidate). Mark all files with M-a, do something similar for files in the other two directories.

  • Or, you can retrieve files in all directories using this pattern: ^hst/\|^inc\|^lib. Helm accepts regex after all. The regex \| means or. Do this if you want to select everything in one go.

With either of these, you will have marked all files you want to open. Then just press RET to open them all.

Please note that if you have lots of files in those directories, you need to increase helm-candidate-number-limit. Otherwise once the number of candidates hits the limit, no more candidates are displayed and you cannot select invisible candidates. Set it to higher number or set to nil if you don't want this limit.

The good thing with Helm is that you can interactively select files.

4
  • I think he wants to open them all simultaneously, not select one of them.
    – Malabarba
    Oct 15, 2014 at 12:51
  • 1
    @Malabarba You can select multiple files with M-a using helm-projectile-find-file and press RET once to open them all using the method I listed.
    – Tu Do
    Oct 15, 2014 at 13:06
  • Of course! Sorry, missed that sentence. I edited to make it a little more obvious to idiots like me. Feel free to rollback if you don't like or if I did something wrong.
    – Malabarba
    Oct 15, 2014 at 13:14
  • @Malabarba Thanks. It's more clear now.
    – Tu Do
    Oct 15, 2014 at 13:37
6

Here are two possibilities (alternatives):

  1. In Dired you can include all of the subdirs containing files you want to act on, either by using ls switches that include -R or by using i to include specific subdirs. If you use library Dired+ then you can use * . (bound to diredp-mark/unmark-extension, to mark all of the listed files that have a given extension (such as .h). Then you can use F (bound to dired-do-find-marked-files) to open all of the marked files.

  2. With library Dired+ you can act on all of the marked files and all of the marked files in marked subdirectories, defined recursively, IOW, subdirs of subdirs, their subdirs, etc.

    For any marked directory, if no files are marked in that directory (i.e., marked in a Dired listing for that subdir) then the action is on all of its files.

    There are a fair number of commands for acting on such files in different ways (opening, searching etc.). But the files to act on are determined only that way; there is not also the possibility of, say, entering a glob pattern or a regexp to filter the set.

    However, if you use library Icicles together with Dired+ then you can use M-+ C-F, i.e., M-+ C-S-f (which is bound to icicle-visit-marked-file-of-content-recursive), to open any or all of the files just described (i.e., those marked or in marked subdirs, defined recursively).

    You can use regexps, on the fly, to filter the file names (and/or the file contents). For example, You can, as you request, open all of the files that have extensions .c, .cc, and .h in the marked subdirs (with marked subdirs being handled the same way, recursively).

5

eshell handles zsh-style **/* glob expansion, so one approach is to fire up eshell in the correct directory and run for f in **/*cc **/*h { find-file $f}

Alternatively, the function find-file supports wildcards when called from elisp. Here's a useful snippet from the documentation for that find-file:

(find-file FILENAME &optional WILDCARDS)
Interactively, or if WILDCARDS is non-nil in a call from Lisp, expand wildcards (if any) and visit multiple files.

I couldn't figure out how to get that to work with zsh-style globbing, but it might be a good option.

If all of these files are in a single source controlled project, projectile might be a different and better approach.

PS. If you go with eshell, I'd suggest binding eshell-toggle-cd to a key so you can easily popup an eshell prompt in the directory of the buffer you're editing.

1
  • I don't think that find-file will operate recursively, which is the main feature I'm after. Opening a shell and typing a command seems like too much work, because (I'm guessing) my command would have to be something like for d in inc src hst { for f in $d/**/*cc $d/**/*c $d/**/*h { find-file $f } } Or is it simpler than that?
    – nispio
    Oct 2, 2014 at 17:00

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.