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 , can be specified multiple
times,’
puts ’ --exclude | -x , can be specified multiple
times,’
puts ’ --base | -b , can be specified
only once;’
puts ’ if given multiple times, the last one
survives;’
puts ’ defaults to current directory,’
puts ’ --filepat | -f , 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