使用Emacs以递归方式查找和替换尚未打开的文本文件

时间:2008-11-07 01:02:58

标签: emacs editor

作为this question的后续行动,它试图找出如何做这样的事情应该很容易,尤其是让我不再习惯使用Emacs,而是启动编辑器。我已经熟悉了。我经常在编辑多个文件时使用这个例子。

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

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

13 个答案:

答案 0 :(得分:348)

  1. M-x find-name-dired:系统将提示您输入根目录和文件名模式。
  2. t为“切换标记”以查找找到的所有文件。
  3. Q进行“文件中的查询替换...”:系统将提示您输入查询/替换正则表达式。
  4. 继续使用query-replace-regexpSPACE替换并转到下一场比赛,n跳过比赛等等。
  5. C-x s保存缓冲区。 (然后,您可以按yn!一次保存所有内容)

答案 1 :(得分:35)

  • M-x find-name-dired RET
    • 所有文件可能需要一段时间才会显示在列表中,滚动到底部(M->),直到出现“find finished”以确保它们都已加载
  • t对所有找到的文件“切换标记”
  • Q进行“文件中的查询替换...”:系统将提示您输入查询/替换正则表达式。
  • 继续使用query-replace-regexp:SPACE或y替换并移至下一个匹配,n跳过匹配等。
    • 类型!替换当前文件中的所有实例而不要求N跳过当前文件的其余部分的所有可能替换。 (N仅限emacs 23+)
    • 要在不进一步询问的情况下对所有文件进行替换,请键入Y
  • 调用“ibuffer”(C-x C-b如果绑定到ibuffer,或M-x ibuffer RET)列出所有打开的文件。
  • 键入* u以标记所有未保存的文件,键入S以保存所有标记的文件
  • * * RET取消标记所有标记,或键入D以关闭所有标记的文件

此答案由this answerthis site和我自己的笔记组合而成。使用Emacs 23 +。

答案 2 :(得分:13)

我通常使用其他工具来执行此任务,似乎EmacsWiki's Find and Replace Across Files entry中提及的许多方法都出现了,但Findr Package看起来很有希望。

窃取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.

答案 3 :(得分:11)

提供的答案很棒,但我认为我会添加一种稍微不同的方法。

这是一种更具互动性的方法,需要wgreprgrepiedit。必须通过MELPA或Marmalade安装ieditwgrep(使用M-x package-list-packages

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

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

接下来,您需要运行wgrepC-s C-p启动它。

Wgrep将允许您编辑rgrep结果,因此在字符串上设置一个区域以匹配并使用iedit-mode启动C-;(根据您的终端,您可能需要重新绑定此)

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

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

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

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

答案 4 :(得分:9)

弹丸非常好: C-c p r运行命令projectile-replace

答案 5 :(得分:5)

使用dired递归深层目录树对于此任务来说会有点慢。您可以考虑使用tags-query-replace。这确实意味着炮轰创建一个标签表,但这通常很有用,而且很快。

答案 6 :(得分:4)

信息来源:1

对于emacs pro用户:

  1. 在dir中调用dired列出文件,或者如果需要所有子目录,则调用find-dired。
  2. 标记您想要的文件。您可以通过键入【%m】来标记正则表达式。
  3. 键入Q以调用dired-do-query-replace-regexp。
  4. 键入查找正则表达式并替换字符串。 〔普通elisp正则表达式〕
  5. 对于每次出现,键入y替换,n键跳过。输入【Ctrl + g】键中止整个操作。
  6. 类型!要在不询问的情况下替换当前文件中的所有匹配项,N将跳过当前文件的其余部分的所有可能替换。 (N仅为emacs 23)
  7. 要在不进一步询问的情况下对所有文件进行替换,请键入Y.(仅限Emacs 23)
  8. 调用ibuffer列出所有打开的文件。输入【* u】标记所有未保存的文件,输入S保存所有标记的文件,输入D将其全部关闭。
  9. Emacs初学者循序渐进指南

    选择目标文件

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

    选择目录中的文件

    首先,您需要选择要替换的文件。使用图形菜单〖文件▸打开目录〗。 Emacs会要求您提供目录路径。输入目录路径,然后按Enter键。

    现在,您将看到文件列表,现在您需要标记您希望正则表达式查找/替换的文件。通过将光标移动到所需文件来标记文件,然后按m。按u取消标记。 (要列出子目录,请将光标移动到目录并按i。子目录的内容将列在底部。)要通过正则表达式标记所有文件,请键入【%m】,然后键入正则表达式图案。例如,如果要标记所有HTML文件,请键入【%m】,然后键入.html $。 (您可以在图形菜单“标记”中找到标记命令列表(当您处于直接模式时会出现此菜单。)

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

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

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

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

    Emacs将通过提示“Run find(with args):”向您询问。如果您需要对所有HTML文件进行替换,请键入-name" * html"。如果您不关心什么类型的文件,只关心该目录下的所有文件,请提供“-type f”。

    现在,按上述方法标记文件。

    互动查找/替换

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

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

    如果要取消整个操作而不保存所做的任何更改,请键入【Ctrl + g】,然后使用菜单〖文件▸退出Emacs〗退出emacs。

    保存更改的文件

    现在,在您完成上述考验之后,您还需要做一个步骤,即保存更改的文件。

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

    如果您使用的是emacs版本21,则可以执行以下操作:调用list-buffers,然后将光标移动到要保存的文件并键入s。它将标记该文件以供以后保存操作。输入u取消标记。完成后,键入x以执行保存标记为保存的所有文件。 (在emacs中,打开的文件称为“缓冲区”。忽略其他内容。)

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

    注意:emacs的正则​​表达式与Perl或Python不同,但类似。有关摘要和常见模式,请参阅:Emacs Regex。

答案 7 :(得分:3)

M-X Dired,并标记所有文件,Q查询所有文件中的替换文字。 您可以在query-replace之前使用i命令展开子目录。 他们添加的关键信息是,如果你给i命令一个前缀(control-u), 它将提示你输入arg,-R参数将以递归方式展开所有subdirs 进入dired缓冲区。所以现在你可以查询 - 搜索整个目录中的每个文件。

答案 8 :(得分:2)

对于开放式缓冲区,这就是我的工作:

(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)))))

答案 9 :(得分:1)

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

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

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

搜索是您定义的搜索上下文 - 您不仅限于搜索目标文件中的所有文本(例如,您可以跳过评论或特定类型的程序部分)。搜索上下文的一个简单示例是一行,如grep中所示,但上下文可以是您喜欢的任何模式匹配的文本块。通常,您使用正则表达式定义搜索上下文,但您可以使用函数。除了定义自己的内容之外,还有针对不同类型的上下文的预定义Icicles搜索命令:文本属性块或覆盖属性,事物点等事物。

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

答案 10 :(得分:1)

find-name-dired没问题,但是:

  • 您获得的所有文件都匹配相同的单一正则表达式。
  • find-dired在这方面更灵活,但它也是为了使用一般规则(即使它们可以是任意复杂的)。当然,find有自己的复杂语言。
  • 如果您希望仅对find(-name)-dired缓冲区中收集了名称的某些文件执行操作,则需要标记它们或删除/省略您不想要操作的行。

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

例如, M-+ Q Q --- query-replace相同,但目标文件是当前目录中标记的所有目标文件标记的子,下,下,下...

是的,使用此类以下命令的替代方法是以递归方式插入所有子目及其子目录,然后使用顶级命令,例如Q。但通常很方便,不要打扰插入的子目录。

要做到这一点,你无论如何都需要一种快速的方式递归插入所有这些子目录。在这里, Dired + 也可以提供帮助。 M-+ M-i 以递归方式插入所有标记的子目录及其标记的子目录。也就是说,它就像M-i(在 Dired + 中插入标记的子目录),但它在子目录上递归。

(所有此类“此处和下方” Dired + 命令位于菜单多个> 标记为此处 。)

您还可以在Emacs 文件集上执行Dired操作,这是一组保存在任何位置的文件名称。如果您使用Icicles,则可以仅为文件集中的文件或其他类型的已保存文件列表打开Dired缓冲区。

您还可以书签任何Dired缓冲区,包括您使用find(-name)-dired创建的缓冲区。这为您提供了一种快速返回此类集合(例如项目集)的方法。如果您使用Bookmark+,则为Dired缓冲区记录(a)其ls个开关,(b)标记了哪些文件,(c)插入了哪些子目录,以及(d)哪个(sub)目录是隐藏的。当您“跳转”到书签时,所有这些都会恢复。 书签+ 还允许您为整个Dired缓冲区树书签 - 跳转到书签会恢复树中的所有缓冲区。

答案 11 :(得分:1)

我想建议一个尚未提及的更好的工具,即 Helm

它是许多涉及完成,搜索等的标准Emacs操作的绝佳替代品。特别是,helm-find-files允许在多个选定文件中执行查询替换(包括regexp)。

只需打开helm-find-files,使用M-SPC标记相关文件,然后使用F6F7在所选文件中运行查询替换或查询替换regexp。

答案 12 :(得分:-2)

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