Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I ran the following to replace a term used in all files in the current working directory:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

This performed the word substitution but it also created .bup files of files that never had the Ms. Johnson string.

How do I perform the substitution without creating all these unnecessary backups?

share|improve this question
    
seems to me as a bug of sed see –  Hotschke Dec 12 '13 at 17:06

4 Answers 4

up vote 1 down vote accepted

You could check the files' contents to make sure that a substitution will take place when sed operates on them:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

If you want to be really clever about it, you could forego using find at all:

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'
share|improve this answer
    
I think you need a '{}' just before your \; in that -exec. –  Jander Nov 21 '11 at 3:13
    
@Jander Thanks. –  amphetamachine Nov 21 '11 at 3:18
    
Thanks! I like the grep solution! –  Belmin Fernandez Dec 7 '11 at 11:28

Find has an -exec operator that executes an arbitrary command. Even better, -exec is a test, so you can chain several -execs together, and if earlier commands fail, later ones won't get executed. The string {} gets replaced with the current filename, and ; marks the end of the command. You should quote both to avoid the shell interfering.

So:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;
share|improve this answer
    
I've never had a problem using bare {}'s. –  amphetamachine Nov 21 '11 at 3:14
1  
@amphetamachine: Neither have I, but the man page suggests it. It could be a csh thing, or there might be shells (not Bash and not POSIX) who expand {} to the null string when doing brace expansion. –  Jander Nov 21 '11 at 5:16

I looked at the man page and didn't see any way to do it directly through sed, as I'm sure you did before asking. I see several ways to work around this using grep, but I think the easiest is this:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-r recurse
-l print filename only
-Z end names with null

share|improve this answer

Seems like you need to build a list of files that match your search terms first.

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done
share|improve this answer
    
You forgot the . as the first argument to find. Also, as I was informed myself not too long ago, you don't actually need to quote or escape the {} –  Kevin Nov 21 '11 at 3:18
    
Don't generate a list of files and perform command substitution on that. First find generates a newline-separated list of files, then the shell breaks up this list at any whitespace (not just newlines) and then the shell treats each word as a glob pattern. This only works if your file names do not contain whitespace or \[?*. Other answers on this page show how to do this correctly. –  Gilles Nov 21 '11 at 23:15
    
@Kevin The . is unnecessary with find (at least find found on linux) because it's assumed when no path is passed an argument. –  laebshade Nov 21 '11 at 23:48

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.