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

Identify Liquid Bottlenecks by Profile Jekyll Builds

It's easy to let Liquid templates get away and bog down build times. Here's a quick way to find out which templates are the culprits.

Aug 19, 2018

Build & Deploy a Dynamic Site in an Hour for Free

Combine the forces of Contentful, Middleman, and Netlify to build and deploy dynamic-like site for free in less than an hour.

May 08, 2018

Use Ruby To Post Content To Slack

Once you learn how to use Slack's incoming webhooks, the possibilities are endless. See how to post to Slack using Ruby.

Feb 07, 2016