Reputation: 5175
How do I replace every occurrence of a string with another string below my current directory?
Example: I want to replace every occurrence of www.fubar.com
with www.fubar.ftw.com
in every file under my current directory.
From research so far I have come up with
sed -i 's/www.fubar.com/www.fubar.ftw.com/g' *.php
Upvotes: 63
Views: 57955
Reputation: 20835
If there are no subfolders, a simpler to remember way is
replace "www.fubar.com" "www.fubar.ftw.com" -- *
where * can also be a list of files.
You need this alias to work as easy as this:
alias replace='function _replace() { from="$1"; to="$2"; shift 2; find . -type f \( -name "$@" \) -exec sed -i "s/${from}/${to}/g" {} +; }; _replace'
(this replace is working now like the SQL command in mySQL)
If you have hidden files with a dot you can add those to *
with
shopt -s dotglob
If you only have one depth of subfolders you can use */*
instead of *
replace "www.fubar.com" "www.fubar.ftw.com" -- */*
Upvotes: 0
Reputation: 101
A more efficient * alternative to the currently accepted solution:
grep "www.fubar.com" . -lr | xargs sed -i 's/www.fubar.com/www.fubar.ftw.com/g'
This avoids the inefficiency of the find . -exec
method, which needlessly runs a sed
in-place replacement over all files below your current directory regardless of if they contain the string you're looking for or not, by instead using grep -lr
. This gets just the files containing the string you want to replace which you can then pipe to xargs sed -i
to perform the in-place replacement on just those files.
* : I used time
to make a cursory comparison of my method with the accepted solution (adapted for my own use case); The find . -exec
-style method took 3.624s to run on my machine and my above proposed solution took 0.156s, so roughly 23x faster for my use case.
Upvotes: 8
Reputation: 1315
When using ZSH as your shell you can do:
sed -i 's/www.fubar.com/www.fubar.ftw.com/g' **/*.php
Upvotes: 0
Reputation: 78105
You're on the right track, use find
to locate the files, then sed
to edit them, for example:
find . -name '*.php' -exec sed -i -e 's/www.fubar.com/www.fubar.ftw.com/g' {} \;
Notes
.
means current directory - i.e. in this case, search in and below the current directory.sed
you need to specify an extension for the -i
option, which is used for backup files.-exec
option is followed by the command to be applied to the files found, and is terminated by a semicolon, which must be escaped, otherwise the shell consumes it before it is passed to find.Upvotes: 110
Reputation: 657
Solution using find, args and sed:
find . -name '*.php' -print0 | xargs -0 sed -i 's/www.fubar.com/www.fubar.ftw.com/g'
Upvotes: 3
Reputation: 6911
A pure bash solution
#!/bin/bash
shopt -s nullglob
for file in *.php
do
while read -r line
do
echo "${line/www.fubar.com/www.fubar.ftw.com}"
done < "$file" > tempo && mv tempo "$file"
done
Upvotes: 2