Was trying to search through files in Ruby and needed to get line numbers along with the matches, similar to grep -n. The grep -n command tells grep to display the line numbers along with each matching line when searching for patterns in a file or standard input.
Turns out there are several ways to do this in Ruby.
Method 1: Using File.readlines with each_with_index
def grep_with_line_numbers(filename, pattern)
File.readlines(filename).each_with_index do |line, index|
puts "#{index + 1}: #{line}" if line.match(pattern)
end
end
grep_with_line_numbers("myfile.txt", /error/)
Method 2: Using File.open with line numbers
def grep_with_line_numbers(filename, pattern)
File.open(filename, 'r') do |file|
line_num = 0
file.each_line do |line|
line_num += 1
puts "#{line_num}: #{line}" if line.match(pattern)
end
end
end
Method 3: One-liner approach
File.readlines("myfile.txt").each_with_index { |line, i| puts "#{i+1}: #{line}" if line =~ /pattern/ }
Method 4: More advanced with multiple files
def grep_files(pattern, *files)
files.each do |filename|
File.readlines(filename).each_with_index do |line, index|
if line.match(pattern)
puts "#{filename}:#{index + 1}: #{line.strip}"
end
end
end
end
grep_files(/error/, "log1.txt", "log2.txt", "log3.txt")
Method 5: Using IO.foreach (memory efficient)
def grep_with_line_numbers(filename, pattern)
line_num = 0
IO.foreach(filename) do |line|
line_num += 1
puts "#{line_num}: #{line}" if line.match(pattern)
end
end
Method 6: Case-insensitive search
def grep_case_insensitive(filename, pattern)
File.readlines(filename).each_with_index do |line, index|
if line.match(pattern, Regexp::IGNORECASE)
puts "#{index + 1}: #{line.strip}"
end
end
end
Method 7: Return results instead of printing
def grep_with_line_numbers(filename, pattern)
results = []
File.readlines(filename).each_with_index do |line, index|
if line.match(pattern)
results << { line_number: index + 1, content: line.strip }
end
end
results
end
matches = grep_with_line_numbers("myfile.txt", /error/)
matches.each { |match| puts "Line #{match[:line_number]}: #{match[:content]}" }
For large files, use IO.foreach:
def grep_large_file(filename, pattern)
line_num = 0
IO.foreach(filename) do |line|
line_num += 1
yield line_num, line if line.match(pattern)
end
end
grep_large_file("huge_log.txt", /error/) do |line_num, line|
puts "#{line_num}: #{line.strip}"
end
Method 8: Using grep command from Ruby
def system_grep(filename, pattern)
result = `grep -n "#{pattern}" #{filename}`
result.split("\n").each { |line| puts line }
end
Method 9: Multiple patterns
def multi_grep(filename, patterns)
File.readlines(filename).each_with_index do |line, index|
patterns.each do |pattern|
if line.match(pattern)
puts "#{index + 1}: #{line.strip} (matched: #{pattern})"
break
end
end
end
end
multi_grep("log.txt", [/error/i, /warning/i, /exception/i])
The IO.foreach approach is best for large files since it doesn't load everything into memory at once. For even better performance with large files, consider using the system grep command directly.