Use rgrep and wgrep (чаще всего)
With rgrep you can search all for a regexp in files which filename match a regexp and inside a directory (and its subdirs)
with wgrep you can edit the buffer containing the results of your rgrep search.
It's a more interactive method, and requires wgrep, rgrep and iedit. Both iedit and wgrep must be installed via MELPA or Marmalade (using M-x package-list-packages)
First run M-x rgrep to find the string you're looking for.
You'll be able to specify file types/pattern and the folder to recurse.
Next you'll need to run wgrep start it with C-s C-p.
Wgrep will let you edit the rgrep results, so set a region on the string to match and start iedit-mode with C-; (depending on your terminal you may need to re-bind this)
All occurrences will be editable at once. C-x C-s to commit wgrep. Then C-x s ! to save the changed files.
The main benefit of this method is that you can use iedit-mode to toggle off certain matches M-;. You can also use the results in rgrep to jump into the files, for example if you have an unexpected match.
I find it very useful for doing source edits and renaming symbols (variables, function names etc.) across a project.
If you don't already know/use iedit mode it's a very handy tool, I strongly recommend you give it a look.
Projectile is really nice: C-c p r runs the command projectile-replace
Прекрасно взял неудобные разрывы строки, с которыми не справляется rgrep.
If you're working on a well-defined project, you can use occur and grep facilities within that project via projectile. Cribbing from its github description, among the various bits of functionality offered by projectile, it can do:
- replace in project
- multi-occur in project buffers
- grep in project
- visit project in dired
M-X Dired, and t to mark all files, and Q to query replace text in all of them. You can expand a sub directory by using the i command before the query-replace. They key info I'm adding is that if you give a prefix (control-u) to the i command, it will prompt you for arg, and -R argument will recursively expand all subdirs into the dired buffer. So now you can query-search every file in an entire directory.
For emacs pro users:
- 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. 〔☛ 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.
Let me mention also Q (dired-do-query-replace) in Dired. Very handy. And be aware that you can easily mark sets of files in Dired using keys such as these (and there are more):
- % m (dired-mark-files-regexp) – mark files whose names match a regexp
- % g (dired-mark-files-containing-regexp) – mark files whose text (content) matches a regexp
- * . (dired-mark-extension) – mark files whose names have the same extension (e.g., .el)
Be sure to load standard library dired-x.el (and perhaps dired-aux.el).
If all of the files are in the same directory
you could follow these steps. I'll base this on the second example given in the comments:
- M-x dired to open the relevant directory in dired mode.
- %m to run dired-mark-files-regexp in that directory.
^dd.*\.sh$, which is the regexp equivalent to dd*.sh. Those files will now be marked with a *, and may also appear highlighted in a different color depending on your color scheme.
- Repeat step 3 as many times as needed, with whatever regexp you want (e.g.
^ee.*\.cls$) until all the files you want to edit are marked.
- Q to run dired-do-query-replace-regexp on the files you marked.
- Enter uncertainty and indeterminacy as the query strings. (I think this will be case-sensitive. If you need it to be case insensitive, that may require a regexp, but I'm not sure.)
And that's the idea. If you need to repeat this a few times in different folders, you can record steps 2-6 as a macro (press C-x ( after step 1, and C-x ) after step 6). And even if you're not very comfortable with elisp, you could translate that macro into elisp using insert-kbd-macro and try to hack it into a useful function.
Ещё из dired
You can use M-x find-name-dired to get a dired buffer containing links to all files matching a given name pattern.
Use M-x find-grep-dired to get a dired buffer containing those files whose contents match the provided grep pattern.
There are many more such commands; which is most appropriate depends on your requirements, so please consider updating your question.
Then you can traverse the list of files using macros. Take a look at Brian's answer for an example: https://emacs.stackexchange.com/a/9497/2005
icicles (которого у меня нет)
Of interest would be moccur-edit and icicles.
In Icicles, C-c ' is command icicle-occur, which can search multiple buffers.
C-u C-c ' searches a set of buffers that you choose. You can choose by dynamically filtering the buffer names with your minibuffer input, then hit C-! to search all of those buffers whose names match. Similarly, C-99 C-c ' searches only the buffers that are visiting files.
Like occur and grep, icicle-occur searches line by line. More generally, instead of using lines as the search contexts you can use any buffer portions at all. C-c ` (backquote instead of quote) is command icicle-search. With a non-negative prefix arg it searches a set of buffers that you choose.
The first thing you do is give it a regexp that defines the search contexts. E.g., if you give it .* then it acts like icicle-occur: each search context is a line. If you give it a regexp that matches only function definitions then those are the search contexts, and so on.