使用emacs的grep功能

本文介绍了如何在Emacs中利用grep功能进行多文件内容搜索,包括常用的grep-find和rgrep命令,以及在Windows环境下如何配置和优化grep体验。文章强调了在Windows下使用grep的注意事项,如大小写敏感问题、文件名通配符解析错误,并推荐使用unxUtils提供的find和grep命令。

作者:winterTTr     转载请注明


emacs中的grep功能


对于使用emacs的人,都希望能将很多的文本相关操作集中到emacs中。那么,文
本处理常常使用的一个功能就是"查找"。

emacs中的常用的查找换功能,包括对当前buffer进行操作的一些,例如
query-replace(M-%),isearch-forward(C-s)等等。

在这里,我们介绍的不是emacs中对当前buffer进行的查找和替换工作,而是介绍
对目录树中的多文件进行查找的功能,那就是grep系列的命令。

我想任何一个使用过linux系列系统的人,对find和grep命令肯定不会陌生。在
emacs中的grep系列的命令,正是对find和grep命令的包装。配合这些函数,我们
能实现快捷的文件内容搜索功能。

grep系列的命令包含很多个,这里简单介绍一些常用的:


  • grep-find

这个命令是根据grep-find-command来调用find执行grep的。

前面是调用的命令,运行时会将光标放在后面(34)标记的位置让你继续输入,然后执行相应的命令。

("find . -type f -exec grep -nH -e  {} \";\"" . 34)


  • rgrep

这个也是我个人使用的最多的一个,用来递归的对目录树进行文件内容查找。
它使用grep-find-template进行命令的调用,在我这里,template的内容为:

"find . <X> -type f <F> -exec grep <C> -nH -e <R> {} \";\""
之所以使用这个最多,主要问题是,emacs对这个命令的调用中,会附加非常丰

富的过滤信息,这样可以过滤掉非常多的不必要的文件。例如:

find . "(" -path "*/SCCS" -o -path "*/RCS" -o -path "*/CVS" -o -path "*/MCVS" -o -path "*/.svn" -o -path "*/.git" -o -path "*/.hg" -o -path "*/.bzr" -o -path "*/_MTN" -o -path "*/_darcs" -o -path "*/{arch}" ")" -prune -o "(" -name ".#*" -o -name "*.o" -o -name "*~" -o -name "*.bin" -o -name "*.bak" -o -name "*.obj" -o -name "*.map" -o -name "*.ico" -o -name "*.pif" -o -name "*.lnk" -o -name "*.a" -o -name "*.ln" -o -name "*.blg" -o -name "*.bbl" -o -name "*.dll" -o -name "*.drv" -o -name "*.vxd" -o -name "*.386" -o -name "*.elc" -o -name "*.lof" -o -name "*.glo" -o -name "*.idx" -o -name "*.lot" -o -name "*.fmt" -o -name "*.tfm" -o -name "*.class" -o -name "*.fas" -o -name "*.lib" -o -name "*.mem" -o -name "*.x86f" -o -name "*.sparcf" -o -name "*.dfsl" -o -name "*.pfsl" -o -name "*.d64fsl" -o -name "*.p64fsl" -o -name "*.lx64fsl" -o -name "*.lx32fsl" -o -name "*.dx64fsl" -o -name "*.dx32fsl" -o -name "*.fx64fsl" -o -name "*.fx32fsl" -o -name "*.sx64fsl" -o -name "*.sx32fsl" -o -name "*.wx64fsl" -o -name "*.wx32fsl" -o -name "*.fasl" -o -name "*.ufsl" -o -name "*.fsl" -o -name "*.dxl" -o -name "*.lo" -o -name "*.la" -o -name "*.gmo" -o -name "*.mo" -o -name "*.toc" -o -name "*.aux" -o -name "*.cp" -o -name "*.fn" -o -name "*.ky" -o -name "*.pg" -o -name "*.tp" -o -name "*.vr" -o -name "*.cps" -o -name "*.fns" -o -name "*.kys" -o -name "*.pgs" -o -name "*.tps" -o -name "*.vrs" -o -name "*.pyc" -o -name "*.pyo" ")" -prune -o  -type f "(" -iname "*.el" ")" -exec grep -i -nH -e ^"\^"autoload\^"^" {} ";"



emacs中grep的一些相关配置

当然对于这些grep的使用中,我们常常会需要对很多特定的功能进行定制。最常
用的就是对find和grep命令执行路径的定制。

grep中也提供了用来定制grep相关功能的命令,例如,我要制定grep和find命令的位置:

(require 'grep)
(setq grep-program "C:\\some-path\\grep.exe")
(setq find-program "C:\\other-path\\find.exe")

当然,我们可以按照自己的想法去定制单个命令的模板:

(require 'grep)
(grep-apply-setting
 'grep-find-command
 '("E:/Tools/Emacs/bin/find.exe . -type f -exec E:/Tools/Emacs/bin/grep.exe -nH -ie  {} NUL \";\"" . 80 ) )
(grep-apply-setting
 'grep-command
 "E:/Tools/Emacs/bin/grep.exe -nH -ie ")
(grep-apply-setting
 'grep-find-template
 "E:/Tools/Emacs/bin/find.exe . <X> -type f <F> -exec E:/Tools/Emacs/bin/grep.exe <C> -nH -ie <R> {} NUL \";\"" )

其实,在这里我虽然列举了办法,我并不建议大家去改动这些默认模板的规则,
因为预定制的很多功能我感觉都非常的不错。而且,原本我需要改变这些规则的
原因,因为在windows下,他们无法找到相应的命令。


在windows下使用emacs中grep功能

下面介绍一下,我在windows中使用emacs功能的一些经验,希望为很多走弯路的朋友提供一些帮助。


  • 定制exec和PATH来代替改变grep|find-program

当然,这条其实多少是一个我个人的习惯,我比较习惯尽量通过构造正确的环
境,让emacs的中的功能能够完整运行,而不是通过改变很多内部变量的设定。

  所以,我推荐将find和grep命令加入emacs的命令查找路径中,这样我们就可以
  完全不用指定任何的find和grep命令的具体路径,就可以正确的调用grep的相
  关命令了。

(wttr/prepend-to-exec-path "directory-of-your-grep-and-find")

具体命令的实现,查看 我的一些工具函数

有关更多的环境变量的设置解释,可以参考这里emacs调用外部命令的环境设置


  • 使用特定的grep风格

关于使用哪种风格,其实没有什么特定的定论,但是在windows下,介于find配
  合xargs有时候常常出现各种各样的问题,例如:cannot fork等等。所以,我
  建议尽量使用exec的风格。

所谓的风格就是运行grep的各种常用的方式,可以查看grep-find-use-xargs变量来

得到更多的帮助。例如:

If `exec', use `find -exec {} ;'.
If `exec-plus' use `find -exec {} +'.
If `gnu', use `find -print0' and `xargs -0'.
Any other value means to use `find -print' and `xargs'.


  我的设置如下:

(require 'grep)
(grep-apply-setting
 'grep-find-use-xargs 'exec)

至于为什么使用这种设定,更多的是因为windows的原因。在windows中,单独使用

grep来进行查找存在俩个问题:

1. grep查找是不能区分文件名的大小写的,我就遇到过怎么都找不到txt文件中的内容

    然后发现,原来是因为实际的文件名是TXT。而find使用的是iname参数,可以使用

    大小写不敏感的文件名。

2. grep在windows下,shell对文件名通配符的解析是有问题的。

    例如: grep -r -i -nH -e "text" *.html

    即便子目录里面有*.html文件并且包含text,这样仍旧是会失败的,报错找不到文件。

    原因我推荐是因为首先*.html被shell在当前目录下展开,结果没有任何文件符合。

    然后再传给grep,结果grep发现没有任何输入文件,于是失败。这个问题,仍旧可以用

   find的结合grep的方式解决。


当然,使用find+grep的方式,也是有缺点的,那就是慢。这点非常的明显,可能是因为

每个文件都需要fork一个grep子进程来进行查找的原因,不过,可用性和效率,非要选一个

的话,我还是先选择可用吧,然后再说效率问题,呵呵。

  • windows下的find和grep命令去哪里找

虽然这个本身并不是个大问题,但是在实际中,的确发现常常很多人去问这个问题。

我建议使用unxUtils,里面包含了非常多的常用命令,基本上可以说一劳永逸。
而且,其他版本的find似乎存在一点问题,但是在这个版本中并没有存在。
下载地址 http://unxutils.sourceforge.net/


  • 我个人的一个patch
我的经验,在windows下使用find结合exec风格配合grep,偶尔总会出现问题。
  这让我对grep这个查找的结果常常非常怀疑,经过一段时间的调查,我想我发
  现了问题的所在。

  据个例子,例如我有如下的命令被emacs调用:

find . -iname "*.cpp" -exec grep -i -nH -e "text *" {} ;

当find找出文件名然后fork出来grep对文件进行查找的时候,fork出来的的
  grep的命令行是如下的形式:

grep -i -nH -e text * <some-file-name-from-find>

我们可以发现,原本的命令行引号被省略掉了,但是这样会造成grep命令的
  调用结果不正确了。介于给出find本身的patch不知道是否会引起其他的调用问
  题,而且需要重新编译,所以我利用advise的功能,直接在emacs中hack它的调
  用方式,很简单,就是多给他一层引号。


(defadvice grep-expand-template (around grep-expand-template-w32-around (template &optional regexp files dir excl))
  "A patch for the windows system, as the [find . -iname \"balabala\" -exec grep \"grep-bala\" {} ;] will
result as a seperate windows process [grep grep-balaba file-name-from-find].
When grep-bala contains *, this will lead to very wierd result as the paramter is not quoted in new process.
So I patch it."
  (if (string-match-p "find.*grep" template)
      (let ((regexp (format "\"%s\"" regexp)))
        ad-do-it)
      ad-do-it))
(ad-activate 'grep-expand-template)


以上~~



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值