views:

131

answers:

2

I found this command line search and replace example:

find . -type f -print0 | xargs -0 sed -i 's/find/replace/g'

It worked fine except it changed the date and file ownership on EVERY file it searched through, even those that did not contain the search text.

What's a better solution to this task?

Thanks.

+2  A: 

Using the -c option (if you are on Linux) ought to cause sed to preserve ownership. As you are using the command, it is in fact rewriting every file, even though it is not making changes to the files that do not contain find.

Isaac
ah just noticed that. Thanks.
Ian
What versions of `sed` have `-c`? My GNU `sed` 4.2.1 doesn't.
Dennis Williamson
I was working from the man page here: http://linux.die.net/man/1/sed -- the man page for sed on a CentOS 4 install I use shows `-c` as an option and `sed --version` reports `GNU sed version 4.1.2`; ditto for a CentOS 5 install where `sed --version` reports `GNU sed version 4.1.5`; MacOSX does not have the `-c` option, which is why I specified Linux.
Isaac
+2  A: 

The easiest way to fix that would be to only execute sed on the files if the contain the text by using grep first:

find . -type f | while read file; do
    grep -q find $file && sed -i 's/find/replace/g' $file
done

This does require reading each file twice (in the worst case), so it might be a little slower. Hopefully, though, your OS should keep the file in its disk cache, so you shouldn't see much of a slowdown, since this process is definitely I/O-bound, not CPU-bound.

Adam Rosenfield
As per Isaac's answer, I'd have to add -c to your solution to prevent the change in ownership, right?
Ian
don't have to use `grep+sed`. sed `'/find/s/find/replace/g'`
ghostdog74
The `grep` was to avoid applying sed at all to files that don't need to be changed and thus avoid changing their modification time.
Isaac