Link to home
Start Free TrialLog in
Avatar of heresy_is_progress
heresy_is_progress

asked on

Replacing a string in multiple files?

Hi,
This is my first EE question. I've searched the Linux TA's before asking, but maybe I haven't been searching the right term, because I haven't come across anything that has helped me yet.

Basically, I need to edit a string in several webpages on several different domains, and doing this manually is very time consuming. I'm wanting a shell script to run that will search all the files in a directory, find the old string and replace it with the new string. I'm fairly new to linux and shell scripting, obviously, so please explain your solution so I can learn from your expertise as well as solve my immediate problem.

Thanks in advance. Love the site so far. I found it a week ago, and have learned a lot just from searching various topics...
ASKER CERTIFIED SOLUTION
Avatar of grblades
grblades
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of heresy_is_progress
heresy_is_progress

ASKER

grblades,
Thanks for the prompt reply. I'm assuming I'll need to run this script from the directory that I'm editing, since there isn't anyewhere that tells it what directory to look for? if so, that isn't a problem; I just wanted to clarify before testing... thanks...
Yes it works in the current directory.
Awesome! it works. Another question, then you get the points:
can I define a variable to the newstring & oldstring? for example

#!/bin/bash
oldstring = '/path/to/oldfile/oldfile'
newstring = '/path/to/newfile/newfile'

allfiles=`ls -1`;
for file in $allfiles ; do
sed -e s/$oldstring/$newstring/ $file > /tmp/tempfile
rm -f $file
mv /tmp/tempfile $file
done

if that is do-able, is my syntax correct? thanks...
I don't follow what you mean. Do you want to take the original string and the string to replace it with from a couple of text files?
If you do then you are almost correct but remember that the ` symbol evaluates the command so if you want to pull the contents of a file into a variable you have to do :-

oldstring = 'cat /path/to/oldfile/oldfile'
newstring = 'cat /path/to/newfile/newfile'

Note that sed is using the '/' character to separate parameters so the search or replace string cannot contain them. Or at least if it does you need to escape them.
The search string is also a regular expression (see man grep for some infor on regular expressions) so matching 192.168.1.2 will find 192.168.1.2 and 192.168.102 (since the . matches any character).
actually, I'm wanting to edit an absolute filepath that's calling up an obsolete include file in a php page. on the actual php script, I'm wanting to change:

include '/old/path/to/includefile';

to

include '/new/path/to/includefile';

so yes, I need to escape the forward slashes(/). What character do I use, a backslash(\)?
Yes you use a backslash. I think you might need quotes around the expression also.

So:-
sed -e "s/\/old\/path\/to\/includefile/\/new\/path\/to\/includefile/" $file > /tmp/tempfile

regular expressions can get very complicated to look at quite quickly ;)


"sed -e "s/\/old\/path\/to\/includefile/\/new\/path\/to\/includefile/" $file > /tmp/tempfile

regular expressions can get very complicated to look at quite quickly ;)"

I'll say. What are all those "'N's" and "V's"? jk...;-D

thanks grblades. I threw on a 50 point bonus for all your help...:-)
I know this is closed, but the following script eliminates having to worry about the regular expression handling.  Since it uses $ substitution, your search and replace strings will not be treated as regexps.  So, you can safely include any characters, except you must "escape" the $ character with a backslash, otherwise it is considered a variable.

You can call this from the command line specifying the parameters, so there's no need to edit the script each time.  Have fun...

Note that in the unlikely event that you already have files named *.greplace, they will be deleted, since greplace uses them as the temporary file.  I could rewrite it with tmpfile....

#!/bin/bash
#
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ] ; then
      echo
      echo "greplace performs a global search and replace on multiple files, recursing directories."
      echo
      echo "USAGE: greplace path filename_pattern search_string replace_string"
      echo "WHERE:"
      echo "        path : path to start search (greplace always recurses)"
      echo "        filename_pattern : pattern of filenames to search - ALWAYS enclose in quotes"
      echo "        search_string : string to search for (ALWAYS enclose in quotes, if it contains '\$' be sure to preceed with backslash."
      echo "        replace_string : string to replace search_string with (ALWAYS enclose in quotes, if it contains '\$' be sure to preceed with backslash."
      exit 192
fi

ALLFILES=`grep -l --directories=recurse --exclude=*~ --include="$2" "$3" "$1"`
echo "Replacing $3 with $4"
for FILE in $ALLFILES ; do
      echo "Processing ${FILE}..."
      rm ${FILE}.greplace &> /dev/null
      touch ${FILE}.greplace
      exec 3< "$FILE"
      while read THISLINE <&3 ; do
            echo "${THISLINE//$3/$4}" >> $FILE.greplace
      done
      exec 3>&-
      mv $FILE ${FILE}~
      mv $FILE.greplace $FILE
done
Oh yeah...forward slashes need to be escaped as well...