Forum: Ruby Grep via Ruby

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
ralf (Guest)
on 2006-02-07 15:08
(Received via mailing list)
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
Robert K. (Guest)
on 2006-02-07 15:20
(Received via mailing list)
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
Fritz Heinrichmeyer (Guest)
on 2006-02-07 15:23
(Received via mailing list)
>
> 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
Jeffrey S. (Guest)
on 2006-02-07 16:03
(Received via mailing list)
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?
Edwin V. (Guest)
on 2006-02-07 16:14
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 :)
ralf (Guest)
on 2006-02-07 16:16
(Received via mailing list)
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
James G. (Guest)
on 2006-02-07 16:31
(Received via mailing list)
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
Jim W. (Guest)
on 2006-02-07 18:17
Edwin van Leeuwen wrote:
> That being said it is ofcourse always fun to write your own script for
> this :)

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'))
Logan C. (Guest)
on 2006-02-07 21:16
(Received via mailing list)
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.
James G. (Guest)
on 2006-02-07 21:41
(Received via mailing list)
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
William J. (Guest)
on 2006-02-07 22:44
(Received via mailing list)
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
Logan C. (Guest)
on 2006-02-07 22:59
(Received via mailing list)
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.
Srinivas J. (Guest)
on 2006-02-08 20:51
(Received via mailing list)
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
Jeffrey S. (Guest)
on 2006-02-11 02:38
(Received via mailing list)
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
This topic is locked and can not be replied to.