使用Emacs以recursion方式查找并replace尚未打开的文本文件
作为这个问题的一个后续,它试图找出如何做这样的事情应该很容易,尤其是阻止我更习惯于使用Emacs,而是启动我已经熟悉的编辑器。 我经常在编辑多个文件时使用这个例子。
在Ultraedit中,我会做Alt + s,然后p显示一个对话框,其中包括以下选项:查找(包括跨多行使用正则expression式),replace为,在文件/types,目录,匹配大小写,匹配整个字,列表更改文件和search子目录。 通常我会先用鼠标点击拖动select我想要replace的文本。
只使用Emacs本身(在Windows XP上),无需调用任何外部工具,如何用*.c
和*.h
文件中的bar \ nbazreplace所有foo \ nbar文件夹以及其下的所有文件夹。 也许Emacs并不是最好的工具,但是如何用最简单的命令轻松完成呢?
-
Mx find-name-dired
:系统会提示您input根目录和文件名模式。 - 按
t
可以find所有文件的“切换标记”。 - 按
Q
“查询replace文件…”:系统将提示您input查询/replace正则expression式。 - 按照
query-replace-regexp
:SPACE
replace并移动到下一个匹配项,n
跳过匹配项等。 - 按
Cx s
保存缓冲区。 (您可以按y
,n
或!
一次保存)
-
Mx find-name-dired RET
- 所有文件出现在列表中可能需要一些时间,滚动到底部(
M->
),直到“find finished
”出现,以确保它们都已经加载
- 所有文件出现在列表中可能需要一些时间,滚动到底部(
- 按
t
可以find所有文件的“切换标记” - 按
Q
“查询replace文件…”:系统将提示您input查询/replace正则expression式。 - 按query-replace-regexp:SPACE或
y
replace并移动到下一个匹配项,n跳过匹配项等。- types! 在不询问的情况下replace当前文件中的所有事件,
N
跳过当前文件的其余部分的所有可能replace。 (N
只是emacs 23+) - 要在没有进一步询问的情况下对所有文件进行replace,请键入
Y
- types! 在不询问的情况下replace当前文件中的所有事件,
- 调用“ibuffer”(如果绑定到ibuffer,则为
Cx Cb
或Mx ibuffer RET
)以列出所有打开的文件。 - 键入
* u
标记所有未保存的文件,键入S
保存所有标记的文件 -
* * RET
取消标记所有标记,或者键入D
closures所有标记的文件
这个答案是从这个答案 ,从这个网站 ,从我自己的笔记。 使用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.
提供的答案是伟大的,但我想我会添加一个稍微不同的方法。
这是一个更互动的方法,需要wgrep
, rgrep
和iedit
。 iedit
和wgrep
必须通过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用户:
- 调用直接在dir中列出文件,或者如果需要所有子目录,则调用find-dired。
- 标记你想要的文件。 你可以用正则expression式来input【%m】。
- 键入Q来调用dired-do-query-replace-regexp。
- 键入您的查找正则expression式并replacestring。 〔☛常见的elisp正则expression式〕
- 对于每个匹配项,inputyreplace,n跳过。 input【Ctrl + g】中止整个操作。
- types! 在不询问的情况下replace当前文件中的所有事件,N跳过当前文件的其余部分的所有可能replace。 (N只是emacs 23)
- 要进行所有文件的replace而不需要进一步询问,请键入Y.(仅限Emacs 23)
- 调用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
标记相关文件,然后使用F6
或F7
运行查询replace或查询replace所选文件中的正则expression式。
find-name-dired
是可以的,但是:
- 所有你得到的文件匹配相同,单个正则expression式。
-
find-dired
在这方面比较灵活,但也可以使用一般规则(即使它们可以任意复杂)。 当然,find
它自己的,复杂的语言。 - 如果您只想对名称在
find(-name)-dired
缓冲区中收集的某些文件执行操作,则需要标记它们或删除/省略那些不想执行操作的行。
另一种方法是使用Dired +命令,这些命令作用于(a)标记的文件和(b) recursionfind的标记的子目录中的所有标记文件(或所有文件,如果没有标记的话)。 这给你两个文件的select普遍性和简单的控制。 这些“在这里和下面”的命令都是在Dired模式下的前缀键M-+
。
例如, M-+ Q
与Q
—查询replace相同,但目标文件都是当前目录中标记的那些文件,以及在任何标记的子目录中,向下,向下,向下…
是的,使用这种在这里和下面的命令的替代方法是recursion地插入所有的子代和它们的子代,然后使用诸如Q
的顶层命令。 但是不用担心插入的子目录会很方便。
要做到这一点,无论如何都需要一个快速的方法来recursion地插入所有这样的子string 。 在这里, Dired +也可以提供帮助。 M-+ Mi
recursion地插入所有标记的子代和它们自己标记的子代。 也就是说,它就像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),使用交互式提示,保存所有修改过的文件的备份,上下文所做更改的日志。 这是我在做大型/全球性更新时倾向于使用的。