sponsor Vim development Vim logo Vim Book Ad

basic Tip #354: Find in files - recursively (NOT :grep!). Only for unix clones.

 tip karma   Rating 19/12, Viewed by 3150 

Read and edit this tip on the Vim tip wiki. The wiki may have a more recent version of this tip.

created:   October 30, 2002 4:31      complexity:   basic
author:   Karthick Gururaj      as of Vim:   5.7

You probably know about the grep command in vim (:help grep)
There is one limitation of this - you can't search for a pattern recursively in files (why doesn't grep have some kind of -R option for searching recursively? Have looked around enough at the man pages for that..). The script below does this. Cut-paste this in to your .vimrc/_vimrc. Type ":Fif" (without arguments) to see usage.

   " Start of script
   " Location where the temporary file (.fif.tmp) would be stored
   let g:Fif_tmp_dir = "/tmp"
   function! Fif_fun(...)
      if a:0 == 0
         " Print usage info and quit
         echo "Usage: Fif <pattern-to-be-searched> <file-pattern>. E.g:"
         echo "Fif struct *.c"
         echo "searches for the word struct in all the c files from the current directory"
         return
      endif
      if a:0 != 2
          echohl Error
          echo "Error! Wrong number of arguments. Type :Fif with no arguments to see usage"
          echohl None
          return
      endif
      let tmp_file = g:Fif_tmp_dir . "/.fif.tmp"
      execute "!touch " . tmp_file . " 2> /dev/null"
      if ! filewritable(tmp_file)
         echohl Error
         echo "No permissions to create " . tmp_file
         echo "Try setting the g:Fif_tmp_dir variable to the right value"
         echohl None
         return
      endif
      " Put quotes around the file pattern
      let com_string = '!find . -name "' . a:2 . '" '
      " Do NOT put quotes around the pattern to be searched - leave it to the user
      let com_string = com_string . '-exec grep -n ' . a:1 . ' /dev/null {} \; > ' . tmp_file
      execute com_string
      if ! filereadable(tmp_file)
         echohl Error
         echo "Can't open " . tmp_file . " for reading"
         echohl None
         return
      endif
      execute "cfile " . tmp_file
      execute '!rm -f ' . tmp_file . ' 2> /dev/null'
   endfunction
   com -nargs=* Fif call Fif_fun(<f-args>)
   " End of script.

No vim magic here, just some shell util usage.
Tested on HPUX.
Should work on Windows with Cygwin. You'll have to
1. Remove those /dev/null's
2. Make sure that the Cygwin's find and grep utils are used, and not the windows ones
3. Change the default value of g:Fif_tmp_dir
4. Cygwin's grep differs from the version I have on HP. For forcing grep to print the filename, you'll have to give it a "-H" option, in addition to "-n"

Some more tinkering can be done with this.. for instance, if you want to search in all the text files, irrespective of the extention, you can consider doing something like this:

   " Find all files.
   let com_string = '!find . -type f -print '
   " Get the file type
   let com_string = com_string . '| xargs file '
   " Filter out the text files
   let com_string = com_string . "| awk '/text/ {print $1}' "
   " Some formatting to remove the trailing ':'
   let com_string = com_string . "| sed 's/://' "
   " grep for the pattern in all the files
   let com_string = com_string . '| xargs grep -n ' . a:1

Cheers!
Karthick.

 rate this tip  Life Changing Helpful Unfulfilling 

<< Swap caps-lock and control keys using MS Windows Registry | Comment Lines according to a given filetype >>

Additional Notes

[email protected], October 30, 2002 4:55
I don't know about grep on HP-UX, but GNU grep *can* recurse into directories using either the "-d recurse", or "--recursive" options.
[email protected], October 30, 2002 21:05
Mea culpa. Maxima culpa. The version of grep I have in HP does *not* have the "-d recurse" feature, but yes, the GNU grep has, and I have the GNU grep now. Thanks for the information.

- Karthick.
PS: Is there a way to remove a tip from these archives?
Anonymous, November 16, 2002 18:02
You can even abbreviate that as -r for GNU grep. I often do something like

    grep -r 'some_func(' .

Really convenient.
shawn at deleurme dot calm., June 13, 2003 12:57
or, if you can't get GNU grep (which you should) you can always use:


find . | xargs grep whatever


[email protected], June 18, 2003 13:21
Or, from within vim:
:grep whatever `find . -name "*.cpp"`

or whatever
Anonymous, August 25, 2003 13:38
Give this a try.

:grep -i "looking for someting"  *.c */*.c *.h */*.h */*/*.h

I think this could work for you, unless I am missunderstanding the problem.

~rs3
If you have questions or remarks about this site, visit the vimonline development pages. Please use this site responsibly.
Questions about Vim should go to the maillist. Help Bram help Uganda.
   
Sponsored by Web Concept Group Inc. SourceForge.net Logo