Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Using a shell like bash or zshell, how can I do a recursive 'find and replace'? In other words, I want to replace every occurrence of 'foo' with 'bar' in all files in this directory and its subdirectories.

share|improve this question
    
An alternative answer for the same questions can be found here stackoverflow.com/questions/9704020/… –  dunxd Feb 13 '13 at 12:00

5 Answers 5

up vote 23 down vote accepted

This command will do it (tested on both Mac OS X Lion and Kubuntu Linux).

# Recursively find and replace in files
find . -name "*.txt" -print0 | xargs -0 sed -i '' -e 's/foo/bar/g'

Here's how it works:

  1. find . -name '*.txt' finds, in the current directory (.) and below, all files whose names end in .txt
  2. | passes the output of that command (a list of filenames) to the next command
  3. xargs gathers up those filenames and hands them one by one to sed
  4. sed -i '' -e 's/foo/bar/g' means "edit the file in place, without a backup, and make the following substitution (s/foo/bar) multiple times per line (/g)" (see man sed)

Note that the 'without a backup' part in line 4 is OK for me, because the files I'm changing are under version control anyway, so I can easily undo if there was a mistake.

share|improve this answer
1  
Never ever pipe find output to xargs without the -print0 option. Your command will fail on files with spaces etc. in their name. –  slhck May 24 '12 at 23:16
    
Why do you need sed -i '' -e 's/foo/bar/g'? Doesn't sed -i 's/foo/bar/g' do the same thing? –  Daniel Andersson May 25 '12 at 7:19
4  
Also, just find -name '*.txt' -exec sed -i 's/foo/bar/g' {} + will do all this with GNU find. –  Daniel Andersson May 25 '12 at 7:20
    
@DanielAndersson - I seem to be getting different results on my work Mac and home Ubuntu machines, so I need to do some more tinkering before I update this answer. One note, though: the find... -exec method is interesting, but man find says to use '-execdir' instead for security reasons. –  Nathan Long May 25 '12 at 13:11
    
Yeah, I've read that remark on -execdir in the manual, but I have never been or heard of anyone who has been bitten, so until then I stay with -exec :-) . That you get different results on Mac OS X and Ubuntu is because Mac OS X does not come with GNU find as standard, and -exec + and the omission of the path are GNU find specific extensions. Perhaps the same could explain some sed discrepancies between the systems. –  Daniel Andersson May 25 '12 at 16:28

Here's my zsh/perl function I use for this:

change () {
        from=$1 
        shift
        to=$1 
        shift
        for file in $*
        do
                perl -i.bak -p -e "s{$from}{$to}g;" $file
                echo "Changing $from to $to in $file"
        done
}

And I'd execute it using

$ change foo bar **/*.java

(for example)

share|improve this answer
find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +

This removes the xargs dependency.

share|improve this answer
1  
This does not work with GNU sed, so will fail on most systems. GNU sed requires you to put no space between -i and ''. –  slhck Jan 16 '13 at 9:59
    
Good point. Fixed. Thanks! –  Ztyx Jan 21 '13 at 10:16

My use case was I wanted to replace foo:/Drive_Letter with foo:/bar/baz/xyz In my case I was able to do it with the following code. I was in the same directory location where there were bulk of files.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

hope that helped.

share|improve this answer

The following command worked fine on Ubuntu and CentOS; however, under OS X I kept getting errors:

find . -name Root -exec sed -i 's/1.2.3.4\/home/foo.com\/mnt/' {} \;

sed: 1: "./Root": invalid command code .

When I tried passing the params via xargs it worked fine with no errors:

find . -name Root -print0 | xargs -0 sed -i '' -e 's/1.2.3.4\/home/foo.com\/mnt/'
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.