Grep via Ruby

R

ralf

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
 
F

Fritz Heinrichmeyer

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

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

what you do is

Regexp.new("/<something>/i")

this is not what you want
 
R

ralf

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
 
E

Edwin van Leeuwen

ralf said:
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 :)
 
J

James Edward Gray II

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 Gray II
 
L

Logan Capaldo

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)


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 Gray II

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.
 
J

James Edward Gray II

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 Gray II
 
W

William James

ralf said:
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??


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
 
L

Logan Capaldo

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

James Edward Gray 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.
 
S

Srinivas Jonnalagadda

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top