I need to recursively look for all files containing a specific string so that I can copy a new file over the old one. E.g.:

If a file has the string "replace me":

  1. find the full path of the files:

  2. replace the file with my new filename.php file.

It sounds simple, but I have wasted several hours on it getting nowhere.

find some/dir \
    -exec grep -q "replace me" {} \; \
    -exec cp some/new/filename.php {} \;
| improve this answer | |
  • I am not sure how to use this. how do I test this output before i run cp? – Scott Elkin Aug 20 '11 at 6:52
  • Put an echo before the cp. – Ignacio Vazquez-Abrams Aug 20 '11 at 6:59
  • @ScottElkin: find can look like black magic, but basically it's just a series of sequential tests or actions that only get run if previous ones return true. You could change the second -exec up to it's closing \; statement to be simply -print to show what was matched by the previous statements. You could also add an "echo" before the cp to print out a preview of the commands that would be run. – Caleb Aug 20 '11 at 7:01
  • this works! I am having the same problem as I said below, where it is finding files I don't want. can I filter the results down to certain php files and ignore the rest? – Scott Elkin Aug 20 '11 at 7:21
  • You can add as many predicates as you like. The find(1) man page details them all. – Ignacio Vazquez-Abrams Aug 20 '11 at 7:28

Ignacio's solution with find is probably the best way. Here it is with all the details from comments incorporated. I am specifically only searching for files (not directories) then grouping three statements together in a group with or statements to match any of the names:

find /dir/ \
    -type f \
    \( -name timthumb.php -or -name thumb.php -or -name rt-timthumb.php \) \
    -exec grep -q "timthumb" {} \; \
    -exec cp filename.php {} \;

However you could also do the finding with just shell glob patterns as well, something like this:

shopt -s extglob
for file in /dir/**{timthumb,thumb,rt-timthumb}.php; do
    grep -q 'timthumb' "$file" && cp filename.php "$file"

You could also use the grep to do the recursive search instead of globbing. This would be useful if you had a lot of files:

grep -l -R -Z 'timthumb' /dir/**thumb.php | while read -d $'\0' file; do
    cp filename.php "$file"

In all cases replace "/dir/" with the base path you want to operate on and "filename.php" with the source file you are going to overwrite with. Quote as necessary. Note that in the last example I used a shortcut to match all files whos names match "*thumb.php". You could do this in the other examples too. In the case of find, you could drop the whole set of OR statements in parens and just use -name '*thumb.php'. All of the above examples will only operate on filesthat match those name patterns AND contain the string 'timthumb'.

| improve this answer | |
  • the first one didn't work. "/dir/**/*.php" is not a directory error. – Scott Elkin Aug 20 '11 at 6:49
  • the second one, when i echo "$file", does not just spit out a path, but a huge list of occurances where it found the string. It is finding non php pages, and find many pages 10+ times since the string occurs multiple times in a page – Scott Elkin Aug 20 '11 at 6:50
  • @ScottElkin: Sorry about that. The first one probably chocked because you don't actually have subdirectories and that was ONLY matching subdirectiries. I edited it to match in the current folder or subdirectories. For the second one you need to use the -l option to grep to output just the file name match. Sorry I missed that typing it up. – Caleb Aug 20 '11 at 6:58
  • wow, caleb, that is great. now it is giving me all the file paths (like I asked), but it is finding other files I wasn't expecting - files that i don't want to overwrite with filename.php. Is there a way to find only files that are named filename.php? – Scott Elkin Aug 20 '11 at 7:15
  • to make sure I don't waste your time - I want to replace all timthumb.php files, along with thumb.php (if 'timthumb' is found within) and rt-timthumb.php. All the rest of the files it finds like log files, function files, I want to ignore. – Scott Elkin Aug 20 '11 at 7:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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