subscribe
Tags:
 
2012
2011
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
2011-07-27

While hacking code and introducing bugs to a project, I sometimes find it necessary to search for a string in every file in a directory. For example, suppose I'm pulling my hair out trying to find where in a drupal project a certain function is called. It could be in a module, or a theme, or the template file. Egads! the code is all over the place and I most certainly do not want to open every damn file and search for the function.

I had been using a script called 'find_in_dir' to help me find a string in a directory and the script is as follows:

find $1 -type f -exec grep -i $2 {} \; -print

The usage of the script was simple:
[jezra@fatlappy ~]$ find_in_dir PATH_TO_SEARCH STRING_TO_FIND

The script would recursively search each file in the directory and output the lines in a file containing the search string and then output the path to the file that was searched. While this definitely did what I needed, I found that I was spending too much time tracking down the path to the file because all of the output was just plain text on the screen.

What I really wanted/needed was something to differentiate the file path in the output from the rest of the output, so I fired up geany and hacked together some Ruby code to do what I need (and output the file path using green text. ohhhhh fancy!)

Enter the Ruby

#!/usr/bin/env ruby

#make a helpy helper function 
def help()
  print "--USAGE--\n"
  print "findindir directory string_to_find\n"
end

#find (
#loc: path to a file or directory,
#string: the string to search for
#)
def find(locstring)
  #is the location a directory?
  if File.directory?(loc)
    #loop through each item in the directory
    Dir.foreach(locdo |name|
      #ignore . and ..
      if name!='.' and name!='..'
        #what is the path of the item?
        path File.join(loc,name)
        #recurse
        find(pathstring)
      end
    end
  else #this is a file 
    #by default, we state that there is no match to the string
    match false
    #loop through each line in the file
    File.foreach(locdo |line|
      #does the line contain our string?
      if line.include?(string)
        match true
        puts line
      end
    end
    #a match was found
    if match
      puts  "\e[32m#{loc}\e[0m\n\n"
    end
  end
end

#set some vars based on user input
start_loc ARGV[0]
string ARGV[1]

#did the user enter enough data?
if start_loc.nil? or string.nil?
  help
else
  #determine the absolute path to the start location
  path File.absolute_path(start_loc)
  #find that shit!
  find(pathstring)
end

Having trouble copying the code? get it at http://hoof.jezra.net/snip/6

The code isn't perfect and could certainly use some improvements, such as:

  • ignore broken symlinks
  • output the line number where matches were found
  • default to current working directory when the user doesn't specify a directory

It may not be the best, but it's a start. Now quit reading and go find something.

Comments
2011-07-27 Kevin Granade:
This get's you most of the way to your solution:
find $1 -type f -exec grep -i $2 {} \; -printf "[%p]\n" | colorit

It has the side effect that it might also colorize other parts of the results, and I didn't quickly see a way to safely remove the brackets after colorization.
2011-07-27 jrobb:
very cool, jez. I'll look through this, ruby seems pretty interesting to me.
2011-07-27 Matt Platte:
It's traditional to condescendingly break out the awk or sed one-liners here but for me, I get some joy - perverse joy, no doubt - in building something with the "wrong tools" that gets the job done anyhow. Good on you, Jezra
2011-07-28 jezra:
If it gets the job done, is it really the wrong tool? Possibly; but this way I'm learning ruby (which is the real goal)
2011-08-15 x1101:
@Jezra you're learning ruby to add another 'wrong' tool to your belt?
2011-08-15 jezra:
A tool is a tool; and the language is growing on me.
2011-09-15 Daniel Kullmann:
grep does that already (although not in green):

grep -ir --color=always pattern directory

the -r recurses through all subdirectories, and --color=always colorises the output.
Name:
not required
Email:
not required (will not be displayed)
Website:
not required (will link your name to your site)
Comment:
required
Please do not post HTML code or bbcode unless you want it to show up as code in your post. (or if you are a blog spammer, in which case, you probably aren't reading this anyway).
Prove you are human by solving a math problem! I'm sorry, but due to an increase of blog spam, I've had to implement a CAPTCHA.
Problem:
2 plus 9
Answer:
required