Here is a small script that I use for my source searches.
JS
* * * *
#!/usr/bin/env ruby
require 'getoptlong'
def generalized_search(ipat, xpat, base = '.', fpat = '*', recurse = true, lor = false)
fns = []
if recurse
fns = Dir.glob("#{base}/**/#{fpat}")
else
fns = Dir.glob("#{base}/#{fpat}")
end
regexp = prepare_regexp(ipat, xpat, lor)
results = []
total_l = 0
total_f = 0
fns.each do |fn|
next if File.directory?(fn)
next unless `file #{fn}` =~ /text/
ln_num = 0
File.foreach(fn) do |line|
ln_num += 1
if eval regexp
results << sprintf("%5d : %s", ln_num, line)
end
end
if results.length > 0
puts
puts ">>> #{fn} : #{results.length} " + (results.length == 1 ? "match" : "matches")
puts
results.each { |ln| print ln }
puts
print ' ', '-' * 75, "\n"
total_f += 1
total_l += results.length
results.clear
end
end
puts
puts "*** Found #{total_l} matching " + (total_l == 1 ? "line" : "lines") + " in #{total_f} " + (total_f == 1 ? "file." : "files.")
puts
total_f
end
def prepare_regexp(ipat, xpat, lor)
regexp = []
if ipat && ipat.length > 0
ipat.each { |pat| regexp << "line =~ /#{pat}/i" }
end
ipattern = lor ? "(#{regexp.join(' or ')})" : "(#{regexp.join(' and ')})"
regexp = []
if xpat && xpat.length > 0
xpat.each { |pat| regexp << "line !~ /#{pat}/i" }
end
xpattern = "(#{regexp.join(' and ')})"
regexp = []
regexp << ipattern if ipattern != '()'
regexp << xpattern if xpattern != '()'
"(#{regexp.join(' and ')})"
end
def print_help
my_name = File.basename($0)
puts
puts " #{my_name} is a utility for quickly finding matching lines in multiple files."
puts " Where #{my_name} is better than a simple grep is in accommodating multiple"
puts ' include and exlude patterns in one go. Similar to egrep, the include and'
puts ' exclude patterns can be regular expressions.'
puts
puts ' Usage:'
puts
puts " #{my_name} OPTIONS"
puts
puts ' where OPTIONS can be'
puts ' --include | -i <include pattern>, can be specified multiple times,'
puts ' --exclude | -x <exclude pattern>, can be specified multiple times,'
puts ' --base | -b <search base directory>, can be specified only once;'
puts ' if given multiple times, the last one survives;'
puts ' defaults to current directory,'
puts ' --filepat | -f <file pattern>, can be specified only once; if given'
puts ' multiple times, the last one survives; defaults to *,'
puts ' --recurse | -r <yes|no>, can be specified only once; if given multiple'
puts ' times, the last one survives; defaults to yes,'
puts ' --lor | -o logically OR the include patterns; default is to logically'
puts ' AND them'
puts ' --help | -h prints this message.'
puts
end
def main
ipat = Array.new
xpat = Array.new
base = '.'
fpat = '*'
rec = true
lor = false
if ARGV.index('--help') or ARGV.index('-h')
print_help
exit
end
begin
opts = GetoptLong.new(['--include', '-i', GetoptLong::OPTIONAL_ARGUMENT],
['--exclude', '-x', GetoptLong::OPTIONAL_ARGUMENT],
['--base', '-b', GetoptLong::OPTIONAL_ARGUMENT],
['--filepat', '-f', GetoptLong::OPTIONAL_ARGUMENT],
['--recurse', '-r', GetoptLong::OPTIONAL_ARGUMENT],
['--or', '-o', GetoptLong::NO_ARGUMENT ],
['--help', '-h', GetoptLong::OPTIONAL_ARGUMENT]
)
opts.each do |opt, arg|
case opt
when '--include', '-i'
ipat << arg.to_s
when '--exclude', '-x'
xpat << arg.to_s
when '--base', '-b'
base = arg.to_s
when '--filepat', '-f'
fpat = arg.to_s
when '--recurse', '-r'
rec = arg.to_s.downcase == 'no' ? false : true
when '--or', '-o'
lor = true
end
end
rescue Exception => e
print_help
exit
end
if ipat.length == 0 and xpat.length == 0
puts
puts '--- Hmm ... looks like you don\'t want to search for any pattern. Quitting!'
puts '--- Try -h if you are looking for some help.'
puts
return
end
res = generalized_search(ipat, xpat, base, fpat, rec, lor)
end
if $0 == __FILE__
main
end