如何在Emacs的目录/子目录中递归搜索/ grep文件内容?


14

我使用Emacs已有一段时间了,但仍然不知为何无法(递归)grep(项目)目录中的字符串并将结果显示为Dired缓冲区或更多内容,这是最好的方法有用的方法。请赐教。


您是否尝试过使用helm-projectile-grep命令(如果已安装头盔弹丸)或projectile-grep
Chakravarthy Raghunandan'8

我不知道是什么helm或者projectile是,但如果它是一个推荐的工具,我会安装并学习它。
鲍里斯·斯蒂尼克

是的,射弹是一个软件包,提供了一种简单的方法来执行命令中提到的问题projectile-grep。另外,我强烈建议您安装helm软件包。我无法想象没有helm和运行emacs helm-projectile。您可能还对helm-ag软件包很感兴趣(该软件包为emacs中的silver search提供了helm界面,据说比grep或ack更快)。
Chakravarthy Raghunandan '16

2
为了使问题对于将来的Google和论坛搜索者更有用和更容易找到,也许考虑考虑修改问题的标题递归地包括单词,并考虑限制范围-例如,如何在目录中递归grep文件内容/子目录。那只是一个例子-可能是其他东西。
法律列表

1
尽管到目前为止的评论和答案已经建议了许多方法来以各种奇特的方式实现此目的,但从您的问题中我看不出为什么简单M-x grep不能满足您的需求。它可以让您提供任意命令行,有时find我需要递归时在此使用。
MAP

Answers:


15

好吧,由于最初的问题没有提及rgrep,因此我将在此处指出。这是Emacs中已经内置的最简单的选项,我发现它对于大多数事情来说已经足够了。

从文档中

Recursively grep for REGEXP in FILES in directory tree rooted at DIR.

搜索仅限于与外壳模式文件FILES匹配的文件名。

所以,举例来说,搜索所有Python文件我的主目录下的用途some_function,我会叫它some_function*.py~/为参数。结果显示在新缓冲区中。


1
可能还想提及find-grep-dired,因为OP提到“结果显示为
Dired

@npostavs我没用过find-grep-dired,请随时将其添加到答案中。
user2699 '16

我曾经尝试过使用ack和ag之类的东西,但前提是我应该从rgrep切换到使用它们的东西,因为它们应该更好。最后,我呆在rgrep上,因为我发现改变毫无益处!在命令行上肯定有一个案例,但是在Emacs rgrep中,针对搜索进行了出色的工作,因此它们之间没有明显的速度差异。(我想说的是,rgrep分步加快在某些情况下,但我不记得是肯定的。)
菲尔斯

1
请注意,next-error并且previous-error可用于和导航结果集。我觉得M-g M-nM-g M-p最方便的标准绑定的。
菲利普斯,2016年

find-grep-dired没有给我一个带有交叉引用链接的缓冲区。rgrep为我做到了,最后的建议next-error previous-error真是太棒了!我唯一的疑问是,所有混乱的命令执行输出都在缓冲区的开头。
罗伯特

11

我愉快地使用M-x find-grep-dired了多年。它将结果作为干燥缓冲区返回,您可以使用它。


我在获取交叉引用链接以进行此操作时遇到了一些困难。它的配置非常讨厌(find-ls-option),毕竟,您最终会得到非常冗长的内容,因为如果没有文件名之前的日期,它将无法正常工作!
罗伯特

5

解决方案1(最佳解决方案):

安装顾问(https://github.com/abo-abo/swiper/blob/master/counsel.el

然后M-x counsel-git-grep

无需任何设置(git知道项目根目录和要排除的文件)。两者git grepcounsel都是有效的。

该项目需要由git管理。

律师需要常春藤模式。

解决方案2:

该解决方案使用grep并适用于任何项目。它比解决方案1差,因为它速度较慢并且需要手动设置。它也基于常春藤模式。

(defvar simple-project-root "~/.emacs.d")
(defun simple-grep ()
  (interactive)
  (unless (featurep 'ivy)
    (require 'ivy))
  (let* ((default-directory (file-name-as-directory simple-project-root))
         (keyword (read-string "Keyword:")))
    (ivy-read (format "Grep at %s:" simple-project-root)
              (split-string (shell-command-to-string (format "grep -rsnI %s ." keyword)) "\n" t)
              :action (lambda (val)
                        (let* ((lst (split-string val ":"))
                               (linenum (string-to-number (cadr lst))))
                          ;; open file
                          (find-file (car lst))
                          ;; goto line if line number exists
                          (when (and linenum (> linenum 0))
                            (goto-char (point-min))
                            (forward-line (1- linenum))))))))

您需要创建.dir-locals.el进行设置simple-project-root,有关技术细节,请参见https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html

解决方案2中的代码只是一个原型。我的实际实现要复杂得多。见counsel-etags-grephttps://github.com/redguardtoo/counsel-etags/blob/master/counsel-etags.el

摘要:

这些是我所知道的最好的两个解决方案。

如果还有其他更好的解决方案,那么他们至少需要解决以下问题才能投入生产,

  • 如何获取grep的关键字(例如,从选定区域获取关键字)

  • 转义关键字

  • 如果存在更有效的grep程序,则应使用它(ripgrep,the_silver_searcher / ag等),否则回退默认grep

  • 候选窗口应使用整个屏幕宽度,并且用户可以交互过滤候选对象(这就是人们使用常春藤或头盔的原因)

  • 我们应该在候选窗口中显示相对路径

  • 能够重用以前的grepped结果。因此,应保存以前的结果。您可以使用ivy-resumefrom ivyhelm-resumefromhelm

  • 保存先前的grepped结果时,也应保存先前结果的上下文。例如,在解决方案2的代码中default-directory是context。有关更多详细信息,请参见https://github.com/abo-abo/swiper/issues/591

  • 应该使用扩展的正则表达式,因为它更简单并且已经被counsel-git-grepthe_silver_searcher / ag使用。


4

我想在也使用@chen bin的解决方案中添加另一个解决方案counsel(但您不需要为此维护项目git)。

您需要安装ag(银色搜索器)并counsel提供counsel-ag用于在当前目录中搜索输入字符串的命令。

如果要在项目中搜索(而不仅仅是当前工作目录),请将其添加到您的.emacs:-

  (defun rag/counsel-ag-project-at-point ()
    "use counsel ag to search for the word at point in the project"
    (interactive)
    (counsel-ag (thing-at-point 'symbol) (projectile-project-root)))

此功能将用于ag递归搜索项目根目录。

编辑:以上功能默认为要搜索的符号。如果您不喜欢这种行为,请替换(thing-at-point 'symbol)nil。如果您想在自己的缓冲区中搜索结果,请按C-c C-o

Edit2:如果已ripgrep安装,则可以在上述功能中替换counsel-agcounsel-rg,就可以了:)


是否projectile-project-root可以找到Rails项目的根目录?
鲍里斯·史提尼克

是的,只要它是有效的射弹项目,它就可以工作。我认为有一些软件包叫做射弹轨道。
Chakravarthy Raghunandan '16

为什么命名函数rag/...
鲍里斯·斯蒂尼克

这是人们在编写自己的函数时经常使用的一种常见样式(如果浏览他们的emacs配置,您会发现很多人正在完成它)。我定义的所有功能都以rag/前缀开头,因此可以在以下位置轻松找到它们M-x:)
Chakravarthy Raghunandan

IC,那就是您的名字:-)
Boris Stitnicky

2

这是一个自定义grep函数的示例,该函数以递归方式捕获目录及其子目录中的文件内容(对搜索词使用正则表达式),并在前后显示上下文行。内置compile.elgrep.el库提供了几种方法来跳转到包含搜索结果的文件中的位置。无需安装任何其他程序即可使此示例正常工作-所需的只是Emacs的完整版本和装有grep实用程序的计算机。如果默认值不足,则grep-program可以将变量调整为指向grep实用程序的特定位置。

(defun recursive-grep ()
"Recursively grep file contents.  `i` case insensitive; `n` print line number;
`I` ignore binary files; `E` extended regular expressions; `r` recursive"
(interactive)
  (let* ((search-term (read-string "regex:  "))
         (search-path
           (directory-file-name (expand-file-name (read-directory-name "directory:  "))))
         (default-directory (file-name-as-directory search-path))
         (grep-command
           (concat
             grep-program
             " "
             "-inIEr --color=always -C2"
             " "
             search-term
             " "
             search-path)))
    (compilation-start grep-command 'grep-mode (lambda (mode) "*grep*") nil)))

虽然该问题并未寻求如何同时修改上述grep函数作为结果返回的多个文件,但我发现使用multiple-cursors和非常有用wgrep。一键修改多个文件变得轻而易举。但是,如果需要这些库,则需要安装这些库。
法律列表

使用此功能而不是内置功能有rgrep什么优势?
npostavs

1
@npostavs-我发现内置的rgrep自定义首选的正则表达式搜索条件非常耗时,因此我选择将所有内容都硬编码到自定义函数中(我每天使用几次)。如果您想写一个替代的答案来描述如何自定义rgrep,这将对将来的其他论坛读者有所帮助。
法律列表
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.