作为这个问题的后续,它试图找出如何做这样的事情,这应该很容易,这尤其阻止我更习惯于使用Emacs,而是启动我已经熟悉的编辑器。在编辑多个文件时,我经常使用这个示例。

在Ultraedit中,我用Alt+s然后p来显示一个带有选项的对话框:查找(包括跨多行使用正则表达式),替换,在文件/类型中,目录,匹配大小写,仅匹配整个单词,列出更改的文件和搜索子目录。通常我会先用鼠标点击-拖动选择我想要替换的文本。

只使用Emacs本身(在Windows XP上),不调用任何外部实用程序,如何替换所有的foo\nbar与bar\nbaz在*.c和*.h文件中的一些文件夹和它下面的所有文件夹。也许Emacs并不是最好的工具,但是如何用最少的命令就能轻松完成呢?


我通常使用其他工具来执行这项任务,EmacsWiki的跨文件查找和替换条目中提到的许多方法似乎都很有用,但Findr包看起来很有前途。

窃取部分源文件:

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

M-x find-name-dired:将提示您输入根目录和文件名模式。 按t“切换标记”找到的所有文件。 按Q“查询-替换文件…”:系统将提示输入查询/替换regexp。 继续执行query-replace-regexp: SPACE替换并移动到下一个匹配,n跳过一个匹配,等等。 按C-x s保存缓冲区。(然后你可以按y表示yes, n表示no,或者!对所有人都是)


对于这个任务,使用dred来递归到一个深目录树将会有点慢。您可以考虑使用标记-查询-替换。这确实意味着要花费一些钱来创建一个标签表,但这通常是有用的,而且是快速的。


M-x find-name-dired RET it may take some time for all the files to appear in the list, scroll to bottom (M->) until "find finished" appears to make sure they all have loaded Press t to "toggle mark" for all files found Press Q for "Query-Replace in Files...": you will be prompted for query/substitution regexps. Proceed as with query-replace-regexp: SPACE or y to replace and move to next match, n to skip a match, etc. 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. Call “ibuffer” (C-x C-b if bound to ibuffer, or M-x ibuffer RET) to list all opened files. Type * u to mark all unsaved files, type S to save all marked files * * RET to unmark all marks, or type D to close all marked files

这个答案结合了这个答案、这个网站和我自己的笔记。使用Emacs 23+。


另一个选择是使用Icicles搜索。这是一种不同类型的增量搜索,它使用对搜索命中的迷你缓冲区输入的完成。当您修改当前输入时,匹配命中的集合将在缓冲区*Completions*中更新。

您可以搜索任意数量的文件、缓冲区或书签位置,您可以使用迷你缓冲区模式(例如regexp)匹配进行选择。

当您访问一个搜索结果时,您可以根据需要替换整个搜索结果或匹配当前小缓冲区输入的部分。按需替换意味着您不会依次查询每个搜索命中;你可以按任意顺序直接访问你想要的点击率。如果要进行的替换数量有限,这种方法可能比查询-替换更有效:跳过详尽的y/n提示。

Search is over search contexts that you define -- you are not limited to searching all of the text in the target files (e.g., you can skip comments or particular kinds of program sections). A simple example of a search context is a line, as in grep, but a context can be any pattern-matched block of text you like. Typically you define the search contexts using a regexp, but you can instead use a function. In addition to defining your own, there are predefined Icicles search commands for different kinds of contexts: blocks of text properties or overlay properties, thing-at-point things, etc.

您还可以以各种排序顺序对搜索命中进行排序,以便于访问/导航。


对于打开的缓冲区,这是我所做的:

(defun px-query-replace-in-open-buffers (arg1 arg2)
  "query-replace in all open files"
  (interactive "sRegexp:\nsReplace with:")
  (mapcar
   (lambda (x)
     (find-file x)
     (save-excursion
       (goto-char (point-min))
       (query-replace-regexp arg1 arg2)))
   (delq
    nil
    (mapcar
     (lambda (x)
       (buffer-file-name x))
     (buffer-list)))))

它不是Emacs,但xxdiff附带了一个名为xx-rename的工具,该工具可以一次对多个字符串执行此操作(例如From To From To From To From To),并带有交互式提示,保存所有修改文件的备份,并生成一个简短的上下文更改日志。这是我在进行大型/全局重命名时倾向于使用的方法。


所提供的答案都很棒,但是我认为我应该添加一个稍微不同的方法。

这是一个更具交互性的方法,需要wgrep, rgrep和iedit。iedit和wgrep都必须通过MELPA或Marmalade安装(使用M-x package-list-packages)

首先运行M-x rgrep查找要查找的字符串。

您将能够指定文件类型/模式和递归的文件夹。

接下来你需要运行wgrep,用C-s C-p启动它。

Wgrep会让你编辑rgrep结果,所以在字符串上设置一个区域来匹配并使用C-启动iedit-mode;(取决于你的终端,你可能需要重新绑定这个)

所有事件都可以立即编辑。C-x C-s来提交wgrep。然后是c x s !保存已更改的文件。

这种方法的主要好处是可以使用iedit-mode关闭某些匹配M-;。您还可以使用rgrep中的结果跳转到文件中,例如,如果您有一个意外的匹配。

我发现它对于在项目中进行源代码编辑和重命名符号(变量,函数名等)非常有用。

如果你还不知道/不使用iedit模式,这是一个非常方便的工具,我强烈建议你去看看。


M-X Dired, t标记所有文件,Q查询替换所有文件中的文本。 在执行query-replace命令之前,可以使用i命令展开子目录。 我添加的关键信息是,如果你给I命令加一个前缀(control-u), 它会提示你输入arg,而-R参数会递归展开所有子dirs 进入干燥的缓冲器。所以现在您可以查询搜索整个目录中的每个文件。


信息来源

对于emacs pro用户:

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.

Emacs初学者逐步指南

选择目标文件

在命令行界面提示符中输入“emacs”启动emacs。(或者,如果您在图形用户界面环境中,双击Emacs图标)

选择目录中的文件

首先,您需要选择要进行替换的文件。使用图形化菜单〖文件回到打开目录〗。Emacs将询问您的目录路径。输入目录路径,然后按Enter。

Now, you will be shown the list of files, and now you need to mark the files you want the regex find/replace to work on. You mark a file by moving the cursor to the file you want, then press m. Unmark it by pressing u. (To list subdirectories, move your cursor to the directory and press i. The sub-directory's content will be listed at the bottom.) To mark all files by a regex, type 【% m】, then type your regex pattern. For example, if you want to mark all HTML files, then type 【% m】 then .html$. (You can find a list of the mark commands in the graphical menu “Mark” (this menu appears when you are in the dired mode).)

选择目录及其所有子目录下的文件

如果你想要查找/替换目录中的文件,包括数百个子目录,这里有一个方法来选择所有这些文件。

find-dired打电话。(通过按【Alt+x】调用命令)然后输入目录名⁖/Users/mary/myfiles

注意:如果您在unix非图形文本终端上使用emacs,并且如果【Alt+x】不起作用,则等效的击键为【Esc x】。

Emacs会提示“Run find (with args):”。如果您需要对所有HTML文件进行替换,则键入-name "* HTML "。如果你不关心文件类型,而只是关心目录下的所有文件,那么给" type f "。

现在,按照上面的描述标记文件。

交互式查找/替换

现在,您已经准备好执行交互式查找替换。为了简单起见,假设你只想用“super”替换“quick”这个词。现在,调用dired-do-query-replace-regexp。它将提示您输入正则表达式字符串和替换字符串。输入“quick”,输入,然后输入“super”。

现在,emacs将使用您的模式并检查文件,并在出现匹配时停止并显示给您。当发生这种情况时,emacs将提示您,您可以选择进行更改或跳过更改。要进行更改,请输入y。要跳过,请输入n。如果只是想让emacs继续对当前文件进行所有此类更改,请输入!。

如果想要取消整个操作而不保存所做的任何更改,输入【Ctrl+g】,然后使用菜单〖File exit emacs〗退出emacs。

保存更改的文件

现在,在经历了上述磨难之后,您还需要执行另一个步骤,那就是保存更改的文件。

如果您使用的是emacs版本22或更高版本,那么调用ibuffer进入缓冲区列表模式,然后键入【* u】标记所有未保存的文件,然后键入S保存所有文件。(shift-s)

如果您使用的是emacs版本21,那么您可以这样做:调用list-buffers,然后将光标移动到您想要保存的文件并键入s。它将标记该文件以供以后保存操作。输入u取消标记。一旦完成,输入x来执行保存所有标记为保存的文件。(在emacs中,打开的文件称为“buffer”。忽略其他事情。)

除了上述选项,您还可以调用save-some-buffers【Ctrl+x s】。然后emacs将显示每个未保存的文件,并询问您是否希望保存它。

注意:emacs的regex与Perl或Python的regex不同,但相似。有关摘要和常见模式,请参见:Emacs Regex。


find-name-dired是可以的,但是:

您得到的所有文件都匹配同一个regexp。 find- dred在这方面更灵活,但它也是为使用通用规则而设计的(即使这些规则可能非常复杂)。当然find也有自己复杂的语言。 如果您希望只对find(name)-dired缓冲区中收集的文件名中的一些文件进行操作,则需要标记它们,或者删除/省略不想操作的那些行。

另一种替代方法是使用dred +命令,作用于(a)标记的文件和(b)标记子目录中所有标记的文件(或所有文件,如果没有标记)…发现递归。这为您提供了对文件选择的通用性和轻松控制。这些“here-and-below”命令都在dred模式下的前缀键M-+上。

例如,M-+ Q与Q——query-replace相同,但目标文件都是在当前目录和任何标记的子目录中标记的文件,down, down, down…

是的,使用这种“这里和下面”命令的另一种方法是递归地插入所有子dirs及其子dirs,然后使用q之类的顶级命令。但是,不使用插入的子dirs通常更方便。

要做到这一点,你无论如何都需要一种快速递归插入所有子dirs的方法。在这方面,Dired+也能提供帮助。M-+ M-i递归地插入所有标记的子dirs和它们自己标记的子dirs。也就是说,它类似于M-i(在Dired+中插入标记的subdirs),但它对subdirs递归地起作用。

(所有这样的“这里和下面”干燥+命令在菜单多个>标记在这里和下面。)

您还可以对Emacs文件集执行Dired操作,Emacs文件集是一组保存的位于任何位置的文件名。如果您使用Icicles,那么您可以为文件集或其他类型的保存文件列表中的文件打开一个Dired缓冲区。

You can also bookmark any Dired buffer, including one that you create using find(-name)-dired. This gives you a quick way to return to such a set (e.g. a project set) later. And if you use Bookmark+ then bookmarking a Dired buffer records (a) its ls switches, (b) which files are marked, (c) which subdirectories are inserted, and (d) which (sub)directories are hidden. All of that is restored when you "jump" to the bookmark. Bookmark+ also lets you bookmark an entire tree of Dired buffers --- jumping to the bookmark restores all of the buffers in the tree.


我想推荐一个还没有被提及的伟大工具,即Helm。

它是许多标准Emacs操作的一个很好的替代品,包括补全、搜索等。特别是,helm-find-files允许在多个选定文件中执行查询替换(包括regexp)。

只需打开helm-find-files,用M-SPC标记相关文件,然后使用F6或F7在所选文件中运行query replace或query replace regexp。


投射弹真的很不错: C-c pr执行投射-替换命令


M-x project-query-replace-regexp RET(确保文件已保存!) M-x rgrep RET然后在每个缓冲区内查询-替换。这很好,因为你可以跟踪所有发生的事情,还因为它让你把搜索限制在某些扩展范围内。