Global search and replace across multiple files

Hi all

I'm in need of a command which can replace a specified string with another string - across multiple files within multiple sub-directories (I intend to run it from / )

I've used the following to get a list of the files:

find . | xargs grep <string1> 

But that's as far as I've got. I've though about using sed but not sure what route to take.

Any suggestion greatly appreciated.

TIA.

If your sed allows the -i switch, you could do something like this:

find . -type f| xargs sed -i 's/old/new/g'

perl has a switch to edit a file in place too. If you have neither, you could use temporary file names and mv the changed file back to the name of the original.

I am not sure if it can be done using some single command. I have tried writing a small ksh shell script. Hope this will help.

#/bin/ksh
for k in `find ./ -type f| xargs grep oldstring
do
   filename=`echo $k | cut -d ":" -f1`
   sed 's/oldstring/newstring/g' $filename >${filename}.bk
   mv ${filename}.bk ${filename}
done

Thanks Sanjay. I tried your example but I keep on getting an error saying that my $ORACLE_HOME isn't set (this is an Oracle db and app server).

Weird thing is that I'm executing this as root from / so why is it asking for a variable to be defined?!

There are a number of problems with sanjaypraj's script:

#/bin/ksh             # Missing ! after #
for k in `find ./ -type f| xargs grep oldstring  # No closing backquote, and expect an Arg list too long error
do
   filename=`echo $k | cut -d ":" -f1`  # not sure why this is needed
   sed 's/oldstring/newstring/g' $filename >${filename}.bk
   mv ${filename}.bk ${filename}  # This is dangerous
done
find . -type -f | while read FILE; do
  sed "s/oldstring/newstring/g" $FILE > $FILE.new
  cp -f $FILE.new $FILE && rm $FILE.new
done
# This is dangerous.  Suppose your "sed" updates an important system file...
$ ls -l rc.tcpip
-rwxrwxr--    1 root     system         6610 Oct 23 09:33 rc.tcpip
 
$ sed "s/old/new/g" rc.tcpip > rc.tcpip.new
 
$ ls -l rc.tcpip.new
-rw-r--r--    1 root     system         6610 Nov 3 10:49 rc.tcpip.new
 
$ mv rc.tcpip.new rc.tcpip
 
$ ls -l rc.tcpip
-rw-r--r--    1 root     system         6610 Nov 3 10:49 rc.tcpip

And when you reboot three months later....

Hi Scottn,
Thanks for reviewing my code and finding the missing stuff, one of which probably because of a copy and paste error (`).
The reason for using

filename=`echo $k | cut -d ":" -f1`

is to cut the filename from the list

If you execute the find command the output i am getting

==> find . -type f | xargs grep hello 
./dir1/file1:hello
./dir1/file2:hello
./dir1/dir2/file4:hello
./dir1/dir2/file5:hello

Ah, of course (why using cut :)). I wasn't using grep, so didn't see that.

Using grep -l would remove the need for cut too.

I'm lucky as this machine is a VM so I can roll back to a snapshot if it all goes horribly wrong! It's a clone of a physical server which is why I'm trying to manually change all references of the oringinal host-name to the new host-name.

Anyway, thank you both for your suggestions.