views:

3148

answers:

7

How to I find and replace every occurrence of:

subdomainA.example.com

with

subdomainB.example.com

in every text file under the /home/www/ directory tree (recursive find/replace).

+10  A: 
cd /home/www && find . -type f -print0 |
  xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Employed Russian
maybe put backslashes before the dots in the first half of the perl s/// substituion, but it's not likely to matter.
Ry4an
+1 for the print0
roe
I'm curious, is there a reason to use `-print0` and `xargs` instead of `-exec` or `-execdir`?
Philipp
There is: from "man find": The specified command is run once for each matched file. That is, if there are 2000 files in /home/www, then 'find ... -exec ...' will result in 2000 invocations of perl; whereas 'find ... | xargs ...' will only invoke perl once or twice (assuming ARG_MAX of about 32K and average file name length of 20).
Employed Russian
@Employed Russian: that's why you'd use `find -exec command {} +` - it does avoid excessive invocations of the command like xargs, but without the separate process.
John Zwinck
On which platform? The xargs solution is portable, the "magic" invocations of "find ... -exec" which do not invoke a subprocess for every file found are not.
Employed Russian
+6  A: 
cd /home/www

find . -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'

UPD.

-print0 (GNU find only) tells find to use the null character (\0) instead of whitespace as the output delimiter between pathnames found. This is a safer option if you files can contain blanks or other special character. It is recommended to use the -print0 argument to find if you use -exec command or xargs (the -0 argument is needed in xargs.).

Fedyashev Nikita
You should have `-print0` and `-0` just in case.
Dennis Williamson
2Dennis: thanks, added.
Fedyashev Nikita
You've added `-0`, but not `-print0`.
Philipp
2Philipp: OK, this was new for me. Some explanation of this 2 parameters was added.
Fedyashev Nikita
+1  A: 
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

find /home/www/ -type f will list all files in /home/www/ (and its subdirectories). The "-exec" flag tells find to run the following command on each file found.

perl -i.bak -pe 's/subdomainA.example.com/subdomainB.example.com/g' {} +

is the command run on the files (many at a time). The "{}" gets replaced by file names. The + at the end of the command tells find to build 1 command for many filenames. From the find man page: "The command line is built in much the same way that xargs builds its command lines."

Thus it's possible to achieve your goal without using xargs -0, or -print0 . .

unutbu
+1  A: 
find /home/www/ -type f -exec \
    sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

Compared to other answers here, this is simpler than most and uses sed instead of perl, which is what the original question asked for.

John Zwinck
+1 for most efficient.
Dan Carley
A: 

muxh more simple way is to use the below on the command line

find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Vijay Sarathi
A: 

sed -i 's/subdomainA/subdomainB/g'grep -ril 'subdomainA' *``

RikHic
A: 

You may also:

Search & replace with find & ed

http://codesnippets.joyent.com/posts/show/2299

(which also features a test mode via -t flag)

eddie