views:

3371

answers:

4

As a follow-up to my question at http://stackoverflow.com/questions/269812/how-to-quickly-get-started-at-using-and-learning-emacs It's trying to find out how to do something like this which should be easy, that especially stops me from getting more used to using Emacs and instead starting up the editor I'm already familiar with. I use the example here fairly often in editing multiple files.

In Ultraedit I'd do Alt+s then p to display a dialog box with the options: Find (includes using regular expressions across multiple lines), Replace with, In Files/Types, Directory, Match Case, Match Whole Word Only, List Changed Files and Search Sub Directories. Usually I'll first use the mouse to click-drag select the text that I want to replace.

Using only Emacs itself (on Windows XP), without calling any external utility, how to replace all foo\nbar with bar\nbaz in *.c and *.h files in some folder and all folders beneath it. Maybe Emacs is not the best tool to do this with, but how can it be done easily with a minimal command?

+4  A: 

I generally use other tools to perform this task, and it seems like many of the approaches mentioned at EmacsWiki's Find and Replace Across Files entry shell out, but the Findr Package looks very promising.

Stealing part of the source file:

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.
Blair Conrad
+1  A: 

Interactively Find and Replace String Patterns on Multiple Files might explain what you ask. Still, it uses find, so it's not exactly what you want.

+26  A: 
  1. M-x find-name-dired: you will be prompted for a root directory and a filename pattern.
  2. Press t to "toggle mark" for all files found.
  3. Press Q for "Query-Replace in Files...": you will be prompted for query/substitution regexps.
  4. Proceed as with query-replace-regexp: SPACE to replace and move to next match, n to skip a match, etc.
Chris Conway
I don't think this is recursive though, no? Otherwise it's a great option for a single directory.
Blair Conrad
No, it's recursive. The non-recursive version would be %m in dired-mode.
Chris Conway
On Windows with GNU Emacs 22.3.1 (i386-mingw-nt5.1.2600), after entering the filename pattern it fails with "find exited abnormally with code 1" – Rob Kam (0 secs ago)
Rob Kam
This is probably a problem with the emacs/find configuration, possibly related to http://www.archivum.info/[email protected]/2005-10/msg00120.html What's the text of the error?
Chris Conway
find . "(" -iname "test.c" ")" -exec ls -ld "{}" ";" Access denied - . File not found - -INAME File not found - TEST.C File not found - ) File not found - -EXEC File not found - LS File not found - -LD File not found - {} File not found - ;
Rob Kam
That's almost certainly an Emacs bug.
Chris Conway
Maybe because you're calling C:\WINDOWS\system32\find.exe, not GNU find.
Jazz
Yes that's it. It works if I get it to use the find.exe from MSYS instead.
Rob Kam
Any hints on how to save all the marked files in the dired-buffer? BTW, thanks for a clear and precise answer: +1
Steen
Steen, I'd like to know that myself. I always switch to the buffer list and save them there ("s" to mark for saving, "x" to save all marked).
Chris Conway
Steen, Chris: Probably not exactly what you want but you can use 'C-x s' (save-some-buffers), it will prompt you for each modified file, so you only have to hit 'y' multiple times.
danielpoe
The reason you get "find exited abnormally with code 1" on Windows is that Emacs shells out to the find command. The default find.exe on Windows will not work, since it isn't compatible with Unix find. To fix, install Cygwin or alternative and ensure that the directory containing the Unix version is in front of the Windows version in the PATH.
Malcolm Sparks
This is brilliant. Thanks +1.
jkp
+2  A: 

Using dired to recurse down a deep directory tree is going to be a bit slow for this task. You might consider using tags-query-replace. This does mean shelling out to create a tags table, but that is often useful anyway, and it's quick.

fivebells