使用Emacs以recursion方式查找并replace尚未打开的文本文件

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

在Ultraedit中,我会做Alt + s,然后p显示一个对话框,其中包括以下选项:查找(包括跨多行使用正则expression式),replace为,在文件/types,目录,匹配大小写,匹配整个字,列表更改文件和search子目录。 通常我会先用鼠标点击拖动select我想要replace的文本。

只使用Emacs本身(在Windows XP上),无需调用任何外部工具,如何用*.c*.h文件中的bar \ nbazreplace所有foo \ nbar文件夹以及其下的所有文件夹。 也许Emacs并不是最好的工具,但是如何用最简单的命令轻松完成呢?

  1. Mx find-name-dired :系统会提示您input根目录和文件名模式。
  2. t可以find所有文件的“切换标记”。
  3. Q “查询replace文件…”:系统将提示您input查询/replace正则expression式。
  4. 按照query-replace-regexpSPACEreplace并移动到下一个匹配项, n跳过匹配项等。
  5. Cx s保存缓冲区。 (您可以按yn!一次保存)
  • Mx find-name-dired RET
    • 所有文件出现在列表中可能需要一些时间,滚动到底部( M-> ),直到“ find finished ”出现,以确保它们都已经加载
  • t可以find所有文件的“切换标记”
  • Q “查询replace文件…”:系统将提示您input查询/replace正则expression式。
  • 按query-replace-regexp:SPACE或yreplace并移动到下一个匹配项,n跳过匹配项等。
    • types! 在不询问的情况下replace当前文件中的所有事件, N跳过当前文件的其余部分的所有可能replace。 ( N只是emacs 23+)
    • 要在没有进一步询问的情况下对所有文件进行replace,请键入Y
  • 调用“ibuffer”(如果绑定到ibuffer,则为Cx CbMx ibuffer RET )以列出所有打开的文件。
  • 键入* u标记所有未保存的文件,键入S保存所有标记的文件
  • * * RET取消标记所有标记,或者键入Dclosures所有标记的文件

这个答案是从这个答案 ,从这个网站 ,从我自己的笔记。 使用Emacs 23+。

我通常使用其他工具来执行这个任务,而且看起来EmacsWiki的“查找和replace跨文件”条目中提到了很多方法,但Findr包看起来非常有前途。

窃取部分源文件 :

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

提供的答案是伟大的,但我想我会添加一个稍微不同的方法。

这是一个更互动的方法,需要wgreprgrepieditieditwgrep必须通过MELPA或Marmalade安装(使用Mx package-list-packages

首先运行Mx rgrep来find你要找的string。

您将能够指定文件types/模式和文件夹进行recursion。

接下来,您需要运行wgrep启动Cs Cp

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

所有的事件都可以一次编辑。 Cx Cs提交wgrep 。 那么Cx s ! 保存更改的文件。

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

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

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

使用dired来caching深层的目录树会对这个任务有点慢。 你可能会考虑使用标签查询replace 。 这确实意味着要创build一个标签表,但无论如何这通常很有用,而且很快。

子弹非常好:Cc pr运行命令弹丸replace

MX Dired ,t标记所有文件, Q查询replace全部文本。 您可以在查询replace之前使用i命令展开子目录。 我添加的关键信息是,如果给i命令一个前缀(control-u),它会提示你inputarg,而-R参数会recursion地将所有的子代码扩展到dired缓冲区中。 所以现在您可以查询search整个目录中的每个文件。

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

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

信息来源: 1

对于emacs pro用户:

  1. 调用直接在dir中列出文件,或者如果需要所有子目录,则调用find-dired。
  2. 标记你想要的文件。 你可以用正则expression式来input【%m】。
  3. 键入Q来调用dired-do-query-replace-regexp。
  4. 键入您的查找正则expression式并replacestring。 〔☛常见的elisp正则expression式〕
  5. 对于每个匹配项,inputyreplace,n跳过。 input【Ctrl + g】中止整个操作。
  6. types! 在不询问的情况下replace当前文件中的所有事件,N跳过当前文件的其余部分的所有可能replace。 (N只是emacs 23)
  7. 要进行所有文件的replace而不需要进一步询问,请键入Y.(仅限Emacs 23)
  8. 调用ibuffer列出所有打开的文件。 input【*】标记所有未保存的文件,inputS保存所有标记的文件,inputD将其全部closures。

Emacs初学者的分步指南

select目标文件

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

select目录中的文件

首先,您需要select要进行replace的文件。 使用graphics菜单〖文件〗▸打开目录〗。 Emacs会问你一个目录path。 input目录path,然后按Enter键。

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

select目录中的文件及其所有子目录

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

调用find-dired。 (通过按【Alt + x】键来调用命令)然后,键入一个目录名称,⁖/ Users / mary / myfiles

注意:如果您在unix非graphics化文本terminal上使用emacs,并且如果【Alt + x】不起作用,等效的按键笔划为【Esc x】。

Emacs会询问你提示符“Run find(with args):”。 如果您需要对所有HTML文件进行replace,请input-name“* html”。 如果你不关心什么types的文件,而只是在该目录下的所有文件,然后给“-type f”。

现在,如上所述标记文件。

交互式查找/replace

现在,您已经准备好进行交互式查找replace。 为了简单起见,我们假设你只是想用“super”来代替“quick”这个词。 现在,请拨打dired-do-query-replace-regexp。 它会提示你input正则expression式string和replacestring。 键入“快速”,input,然后“超级”。

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

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

保存更改的文件

现在,经过上述考验之后,还需要再做一步,那就是保存已更改的文件。

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

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

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

注意:emacs的正则​​expression式与Perl或Python的不同,但是相似。 有关总结和常见模式,请参阅:Emacs正则expression式。

另一个select是使用冰柱search 。 这是一种不同types的增量search,使用完成对search匹配的迷你缓冲区input。 在修改当前input时,匹配匹配集将在缓冲区*Completions*更新。

您可以search任意数量的文件,缓冲区或书签位置,您可以使用小型缓冲区模式(例如正则expression式)匹配来select。

当您访问search结果时,您可以根据需要replace整个匹配或仅匹配当前小型缓冲器input的匹配部分。 按需更换意味着不会查询每个search结果; 您可以以任何顺序直接访问您想要的匹配。 这种方法可以比查询replace更有效,如果您的replace数量有限:您可以跳过详尽的y/n提示。

search是在您定义的search上下文之上 – 您不限于search目标文件中的所有文本(例如,您可以跳过注释或特定种类的程序部分)。 search上下文的一个简单例子是一行,就像在grep ,但是上下文可以是任何你喜欢的模式匹配的文本块。 通常使用正则expression式来定义search上下文,但也可以使用函数。 除了自定义之外,还有预定义的冰封search命令用于不同types的上下文:文本属性块或覆盖属性块,事物点事物等等。

您还可以按各种sorting顺序对search结果进行sorting,以便于访问/导航。

我想提出一个尚未提到的更好的工具,即Helm

它是许多标准Emacs操作的完美替代品,涉及完成,search等。特别是, helm-find-files允许在多个选定文件中执行查询replace(包括正则expression式)。

只需打开helm-find-files ,用M-SPC标记相关文件,然后使用F6F7运行查询replace或查询replace所选文件中的正则expression式。

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

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

另一种方法是使用Dired +命令,这些命令作用于(a)标记的文件和(b) recursionfind的标记的子目录中的所有标记文件(或所有文件,如果没有标记的话)。 这给你两个文件的select普遍性和简单的控制。 这些“在这里和下面”的命令都是在Dired模式下的前缀键M-+

例如, M-+ QQ —查询replace相同,但目标文件都是当前目录中标记的那些文件,以及在任何标记的子目录中,向下,向下,向下…

是的,使用这种在这里和下面的命令的替代方法是recursion地插入所有的子代和它们的子代,然后使用诸如Q的顶层命令。 但是不用担心插入的子目录会很方便。

要做到这一点,无论如何都需要一个快速的方法来recursion插入所有这样的子string 。 在这里, Dired +也可以提供帮助。 M-+ Mirecursion地插入所有标记的子代和它们自己标记的子代。 也就是说,它就像Mi (在Dired +中插入标记的子目录),但它在子目录上recursion执行。

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

您也可以对Emacs 文件集执行Dired操作,这是一组保存在任何地方的文件名称。 如果你使用冰柱,那么你可以打开一个Dired缓冲区,只是在一个文件集或其他types的文件列表中的文件。

您也可以为任何Dired缓冲区添加书签 ,包括使用find(-name)-dired创build的find(-name)-dired 。 这给你一个快速的方法,稍后返回到这样的一套(如一个项目集)。 如果您使用书签+然后书签一个Dired缓冲区logging(a)其ls开关,(b)哪些文件被标记,(c)哪些子目录被插入,以及(d)哪些(子)目录被隐藏。 所有这些在您“跳转”到书签时都会被恢复。 书签+还可以让您为Dired缓冲区的整个树进行书签—跳转到书签可恢复树中的所有缓冲区。

这不是Emacs,但是xxdiff带有一个名为xx-rename的工具,它可以一次对多个string进行处理(例如From To from到FROM TO),使用交互式提示,保存所有修改过的文件的备份,上下文所做更改的日志。 这是我在做大型/全球性更新时倾向于使用的。