Grep via Ruby


#1

Hi,
I’d like to have a “grep” with case-insensitive match. normal grep does
not have this functionality (afaik), but ruby does. So this is, what i
wrote:

cat rgrep:
#!/usr/bin/env ruby

Grep with full regexp-functionality via ruby

if ARGV.shift == “-p”
pattern = Regexp.new(ARGV.shift)
else
puts “Please give me a pattern with the ‘-p’ option”
exit
end
ARGV.each do |filename|
File.open(filename) do |file|
file.each do |line|
puts “#{filename} #{file.lineno.to_s}: #{line}” if
pattern.match(line)
end
end
end

Using it via: rgrep -p ‘/delete /i’ *.php does not match anything, but
this
#!/usr/bin/env ruby

Grep with full regexp-functionality via ruby

if ARGV.shift == “-p”
pattern = Regexp.new(ARGV.shift)
else
puts “Please give me a pattern with the ‘-p’ option”
exit
end
ARGV.each do |filename|
File.open(filename) do |file|
file.each do |line|
puts “#{filename} #{file.lineno.to_s}: #{line}” if /delete
/i.match(line)
end
end
end

DOES match. Does anyone see the bug? Maybe this can be done a lot
easier by using ARGF??

Thanks in advance
Ralf
Müller


#2

ralf wrote:

Hi,
I’d like to have a “grep” with case-insensitive match. normal grep
does not have this functionality (afaik), but ruby does.

14:14:49 [~]: grep -i foo <<EOF

foo
FOO
EOF
foo
FOO
14:14:58 [~]:

robert

#3

DOES match. Does anyone see the bug?
//i is syntactic shugar for

Regexp.new(, flag-for-case-insensitive-i-cannot-remember)

what you do is

Regexp.new("//i")

this is not what you want


#4

ralf wrote:

Hi,
I’d like to have a “grep” with case-insensitive match. normal grep does
not have this functionality (afaik), but ruby does. So this is, what i

Grep does have this functionality with the i switch.
grep -i

That being said it is ofcourse always fun to write your own script for
this :slight_smile:


#5

I meant the command-line tool. I thought, that ‘grep’ should get the
‘ignore-case’ flag by the pattern like in ruby/perl and didn’t thaught
about the command-line options. :((
Sorry for this so-damn-simple question.

regards
Ralf


#6

On Feb 7, 2006, at 7:08 AM, ralf wrote:

I’d like to have a “grep” with case-insensitive match.

You can turn options on/off inside a pattern. For example, here is a
pattern that matches the word file, regardless of case:

(?i:file)

Maybe this can be done a lot easier by using ARGF??

Yes it can. Your input loop can be replaced with:

ARGF.grep(pattern) do |line|
puts “#{ARGF.filename} #{ARGF.lineno}: #{line}”
end

Hope that helps.

James Edward G. II


#7

ralf wrote:

I’d like to have a “grep” with case-insensitive match. normal grep does
not have this functionality (afaik), but ruby does.

Are you talking about Enumerable#grep or the grep command-line tool?


#8

On Feb 7, 2006, at 9:30 AM, James Edward G. II wrote:

Minor suggestion, line is going to end in an nl anyway. I would use
print, unless you want all that extra whitespace in the output.


#9

On Feb 7, 2006, at 1:13 PM, Logan C. wrote:

Minor suggestion, line is going to end in an nl anyway. I would use
print, unless you want all that extra whitespace in the output.

puts() adds a newline character only if the string didn’t already end
in one.

James Edward G. II


#10

Edwin van Leeuwen wrote:

That being said it is ofcourse always fun to write your own script for
this :slight_smile:

Heh, I wrote something similar the other day to search for stuff in the
most recent rails code base installed on a box.

Here is my version of grep.rb…

require ‘rake’
FileList[ARGV[1…-1]].egrep(Regexp.new(ARGV[0], ‘i’))


#11

ralf wrote:

pattern = Regexp.new(ARGV.shift)
end
puts “Please give me a pattern with the ‘-p’ option”

DOES match. Does anyone see the bug? Maybe this can be done a lot
easier by using ARGF??

if ARGV.shift == “-p”
pattern = Regexp.new(ARGV.shift,Regexp::IGNORECASE)
else
puts “Please give me a pattern with the ‘-p’ option”
exit
end

puts "#{$FILENAME} #{$.}: #{$}" if $ =~ pattern while gets


#12

On Feb 7, 2006, at 2:39 PM, James Edward G. II wrote:

On Feb 7, 2006, at 1:13 PM, Logan C. wrote:

Minor suggestion, line is going to end in an nl anyway. I would
use print, unless you want all that extra whitespace in the output.

puts() adds a newline character only if the string didn’t already
end in one.

James Edward G. II

Egads! Surely you jest!

% irb
irb(main):001:0> puts “Hello\n”
Hello
=> nil
irb(main):002:0> puts "Hello\n "
Hello
=> nil

You jesteth not. And to think this whole time I’ve been typing print
when I could have been typing puts.


#13

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


#14

ralf wrote:

I meant the command-line tool. I thought, that ‘grep’ should get the
‘ignore-case’ flag by the pattern like in ruby/perl and didn’t thaught
about the command-line options. :((
Sorry for this so-damn-simple question.

Try:

grep -i

And of course, see the manual page:

man grep