Michael Wei
Michael Wei

Reputation: 43

Replace Text In All files Within a Directory/Subdirectories In Emacs?

I need to replace a certain string in all the files within a directory, which has subdirectories with files also needing to be replaced. Is there a way to accomplish this in Emacs?

Upvotes: 4

Views: 2620

Answers (3)

Xah Lee
Xah Lee

Reputation: 17555

Plain emacs:

  • Call dired to list files in dir, or call find-dired if you need all subdirectories.
  • Mark the files you want. You can mark by regex by typing 【% m】.
  • Type Q to call dired-do-query-replace-regexp.
  • Type your find regex and replace string. 〔➤see common elisp regex pattern〕
  • For each occurrence, type y to replace, n to skip. Type 【Ctrl+g】 to abort the whole operation.
  • Type ! to replace all occurrences in current file without asking, N to skip all possible replacement for rest of the current file. (N is emacs 23 only)
  • To do the replacement on all files without further asking, type Y. (Emacs 23 only)
  • Call ibuffer to list all opened files.
  • Type 【* u】 to mark all unsaved files, type S to save all marked files, type D to close them all.

more detail at http://ergoemacs.org/emacs/find_replace_inter.html


Alternatively, I wrote a package just for this. See: http://ergoemacs.org/emacs/elisp-xah-find-text.html I arrived it after 5 years trial'n'error of all ways to do this.

It's entirely implemented in emacs lisp, not dependent on shell find/grep/sed etc. So works fine in Windows. Also, it does find/replace in one shot, with colored report. So it's fast and lets you quickly check result just in case. Backup is optionally made.

Upvotes: 4

jpkotta
jpkotta

Reputation: 9437

I generally do this the way @lawlist suggests. Here it is step-by-step:

  1. Install wgrep from Melpa or some other way. I recommend also wgrep-ag and ag if you use The Silver Searcher.

  2. Use M-x rgrep (or M-x ag) to search the files and get a list of lines to potentially change.

  3. In the *grep* buffer, run M-x wgrep-change-to-wgrep-mode. I bind this to C-x C-q in grep-mode-map.

  4. Use query-replace-regexp (C-M-%), or do any other editing in the *grep* buffer.

  5. Save the *grep* buffer with C-x C-s. Use C-c C-k to abort. The changes exist only in the *grep* buffer until you save it. You can re-enable wgrep mode any number of times.

  6. All of the files in the grep search now have open buffers with modifications to them if you saved the *grep* buffer. Do C-x s to save all of them to disk.

Upvotes: 6

Juancho
Juancho

Reputation: 7372

A way to do this interactively is to get a directory listing of all files, mark those you are interested in (may be the whole lot), and then run a query-replace on all of them.

Something like this:

  1. Run find-dired on your directory, with arguments -type f to get files and not directories (you can further filter here by type with something like -type f -name "*.txt"). This will get you a dired listing with all files.
  2. Mark all files (T will do by toggling marks), or mark files containing specific text (with % g).
  3. Now run a query-replace-regexp on all marked files with S-Q (uppercase Q).

If the query-replace goes well, you can speed up by typing ! to continue without asking.

Upvotes: 5

Related Questions