Executing rgrep non-interactively
I'm trying to run the rgrep command from a small Emacs Lisp utility, but I'm getting an odd error. The command description is:
rgrep is an interactive compiled Lisp function.
(rgrep REGEXP &optional FILES DIR CONFIRM)
Recursively grep for REGEXP in FILES in directory tree rooted at DIR. The search is limited to file names matching shell pattern FILES. FILES may use abbreviations defined in
grep-files-aliases', e.g. entering
ch' is equivalent to `*.[ch]'.With C-u prefix, you can edit the constructed shell command line before it is executed. With two C-u prefixes, directly edit and run `grep-find-command'.
Collect output in a buffer. While find runs asynchronously, you can use C-x ` (M-x next-error), or RET in the grep output buffer, to go to the lines where grep found matches.
This command shares argument histories with M-x lgrep and M-x grep-find.
I try to run:
(rgrep "something" "all" "~/projects/")
and I get
*** Eval error *** Wrong type argument: stringp, nil
Obviously all the params are strings, so I cannot understand where i开发者_Python百科s this nil coming from.
I'm running Emacs 23.3 on Debian Testing.
Thanks in advance for your help!
i think it's because you have no 'grep-find-template' defined. this is certainly (having debugged) why the command produces the error on my version. look at the help for that variable.
cheers.
ps. it's the difference between calling it interactively or not..
"find . <X> -type f <F> -print0 | \"xargs\" -0 -e grep <C> -nH -e <R>"
..gets set by 'grep-calc-defaults' when called interactively
pps. i think you just have to be careful with your call. if no matches are found, you'll get a 'Grep exited abnormally with code 123' error.
mkdir -p ~/a/b
cp ~/.bash* ~/a/b
emacs -q
C-x b <RET> *scratch*
(grep-compute-defaults)
(rgrep "^.*\\?\=.*$" "*bash*" "~/a")
..lots of matches!
The reason you get this when you call rgrep
programmatically is that all the interactive
calls to the variants of grep
have a call to grep-compute-defaults
in the interactive
call. This does not get evaluated when you're calling programmatically.
The easiest way to fix this is to add
(eval-after-load "grep"
'(grep-compute-defaults))
in your code, which will force that to be called (but only when needed).
The following appears to work ok for me:
(defadvice rgrep (around rgrep-init)
"Init grep defaults before calling rgrep non-interactively."
(when (not (called-interactively-p))
(grep-compute-defaults))
ad-do-it)
(ad-activate 'rgrep)
(rgrep "something" "all" "~/projects/")
According to the Emacs manual:
The commands M-x lgrep (local grep) and M-x rgrep (recursive grep) are more user-friendly versions of grep and grep-find, which prompt separately for the regular expression to match, the files to search, and the base directory for the search.
For the problem at hand, we don't need this 'user-friendliness' which gets in the way. We can use the plain "grep" elisp function which is better suited for non-interactive use. Basically this function takes as argument whatever grep command line you'd have to use to achieve the desired result. Maximum flexibility!
Here's what it would look like for your scenario:
(grep "grep --color -rn something ~/projects/")
Here's another, more complex use of grep's options, to match only complete words in Python files:
(grep "grep --include=\"*.py\" --color -rnw your_pattern files_root_dir")
精彩评论