Picture of Brian Love wearing black against a dark wall in Portland, OR.

Brian Love

Find-and-Replace in Multiple SVN Repositories

A bash shell script to find-and-replace in all files in multiple svn repositories.

Here is what I wanted the script to do:

Walkthrough

The first thing I needed to do was to define some constant variables to hold some values, such as the root SVN URL, the path to store the working copies, and the names of all of the repositories.

# Define constants
BASE_URL="http://svn.example.com/"
ROOT="/Users/brian/repos/"
REPOSITORIES=("Access" "Accessibility" "Adobe" "Ajax" "Apache" "CSS")

The next thing I do is prompt the user for the necessary values. I am then escaping the find and replace values for any special regular expression characters.

# Prompt the user for the find value
read -p "What value would you like to replace? " find
find_regex=$(echo "${find}"|sed 's!\([]\*\.\$\/&[]\)!\\\1!g')

# Prompt the user for the replace value
read -p "What value do you want to replace this with? " replace
replace_regex=$(echo "${replace}"|sed 's!\([]\*\.\$\/&[]\)!\\\1!g')

# Prompt the user to enter the commit message
read -p "Enter a commit message for all updates: " commit_message

Now it’s time to loop over each of the repositories. Doing the svn checkout and update is easy enough, but the find and replace was a little tricky.

# Loop over each repository
for i in "${REPOSITORIES[@]}"
do
  #set variables for each iteration
  url="${BASE_URL}${i}/trunk"
  path="${ROOT}${i}"

  #do checkout
  echo "checkout:  ${url}"
  svn checkout "${url}" "${path}"

  #do find and replace
  echo "replacing '${find}' with '${replace}'"
  grep -lr --exclude-dir=".svn" -e "${find}" "${path}" | xargs sed -i '' -e "s/${find_regex}/${replace_regex}/g"

  #do commit
  echo "committing"
  svn commit -m "${commit_message}" "${path}"
done

Complete Script

#!/bin/bash

# Define constants
BASE_URL="http://svn.example.com/"
ROOT="/Users/brian/repos/"
REPOSITORIES=("Access" "Accessibility" "Adobe" "Ajax" "Apache" "CSS")

# Prompt the user for the find value
read -p "What value would you like to replace? " find
find_regex=$(echo "${find}"|sed 's!\([]\*\.\$\/&[]\)!\\\1!g')

# Prompt the user for the replace value
read -p "What value do you want to replace this with? " replace
replace_regex=$(echo "${replace}"|sed 's!\([]\*\.\$\/&[]\)!\\\1!g')

# Prompt the user to enter the commit message
read -p "Enter a commit message for all updates: " commit_message

# Let the user know we are starting
echo "Thanks. We are going to replace all instances of '${find}' with '$replace'."
echo "OK, let's check out all of the SVN repositories. Please be patient..."

# Loop over each repository
for i in "${REPOSITORIES[@]}"
do
  #set variables for each iteration
  url="${BASE_URL}${i}/trunk"
  path="${ROOT}${i}"

  #do checkout
  echo "checkout:  ${url}"
  svn checkout "${url}" "${path}"

  #do find and replace
  echo "replacing '${find}' with '${replace}'"
  grep -lr --exclude-dir=".svn" -e "${find}" "${path}" | xargs sed -i '' -e "s/${find_regex}/${replace_regex}/g"

  #do commit
  echo "committing"
  svn commit -m "${commit_message}" "${path}"
done

Download

If you would like to download the full script, here you go:

Download

Just extract the zip and set it to be executable:

$ chmod +x find-and-replace.sh