Search and Replace Multiple Lines in Multiple Files in Ruby

There are many tools for searching and replacing, but most don't support changing multiple lines in one process.

There are a lot of tools out there for searching and replacing across multiple files. Heck, even the code editor I'm using now -- VS Code -- supports search and replace (and it's pretty quick about it).

But when I recently went to search and replace a multi-line string in all files throughout a directory, I noticed there was a lack of tools to accomplish this. The sed command won't do it and neither will my code editor (at least at the time of writing this).

It turns out this is quite easy to accomplish in ruby with an ad hoc script using the Dir class to identify the files and the File class to read and rewrite the file.

Before we get into the guts of this thing, know that this can be a dangerous path down which to proceed. This particular approach is a destructive action and if you're not using version control and you write an error into your script, you could incorrectly and permanently alter files in a negative way. I highly recommend tracking these files with git so you can protect against mistakes.

Writing the Script

Let's consider an instance where you want to remove a particular string ("Hello World") followed by two newlines (i.e. a multi-line search and replace), but we only want to make this change within ruby files within the current directory and all subdirectories.

Our script could look something like this:

# The string we want to replace.
str = "Hello World\n\n"
# Find all ruby files in this directory and its subdirectories.
Dir.glob('./**/*.rb').each do |file|
# Read the file and store the contents in memory.
content = File.read(file)
# Don't do anything ("next")
next unless content.include?(str)
# (Re)Write the file after removing the targeted string.
File.open(file, 'w+') { |f| f.write(content.remove(str)) }

Running the Script

Where you put this script so it can be run is entirely up to you and the way in which you like to work. In general, there are three solid ways in which you can run a ruby script:

  1. Open an IRB instance, paste the command and then run it.

  2. Put the command in a file, and then run ruby path/to/file.rb where path/to/file.rb is the path to your ruby file.

  3. Make it a rake task.

In general, if it's a one-off task you're only going to run a single time, the IRB console is usually the way to go. That way you don't have to store any code. You write it, run it, and then forget about it.

If it's something you're going to run again, or if you may use something similar to it in the future, it may be worth storing as a standalone script or an executable.

Once you've run the script, go check your files and see that your targeted string has been removed!

Let's Connect

Keep Reading

Round to the nearest 0.5 in Ruby

A cool and quick trick to round floats to the nearest 0.5 in Ruby.

Nov 01, 2014

A Quicker Way to Compare Multiple Equals Operators in Ruby

When you attempt to write several predictable comparisons in one statement, it gets ugly fast. Here are some methods for cleaning it up.

Apr 20, 2015

Bulk Resize Images Using Rake and ImageMagick

Got a set of images you need all to conform to the same size? Hate doing it manually? Me too. Let's write a rake task to solve our challenge.

Feb 15, 2016