I think this is a great way of doing substitutions in multiple files because you get to see a preview of what it looks like before you actually writing it to disk.
This is great for a small number of files, but to do a large directory of files, you don't really gain any advantages as you're probably not going to open every file in a vim buffer and review each one separately.
This is where sed and find come in handy!
This command will replace every occurrence of the word "foo" with the word "bar" in all html files recursively from the current directory:
find . -name "*.html" -exec sed -i "s/foo/bar/g" '{}' \;
The explanation:
This might look a little confusing, but it essentially 2 parts:
The first part will list all the .html files recursively and for each one, execute the command specified by the -exec option:
find . -name "*.html" -exec ...
The second part is the command to execute for each found file, which in this case is sed:
sed -i "s/foo/bar/g" <TheFile>
The '{}' represents the current file and the \; represents the end of the command to execute as part of the -exec option.
Doing more:
As you can see, the -name option to the find command takes a glob pattern.
If you wanted to be more specific about which files should have the substituion, you could use a regular expression instead, like this:
find . -regex ".*[.]html\|.*[.]js" -exec sed -i "s/foo/bar/g" '{}' \;
This regex will match all files that end with ".html" or ".js".
If you wanted to preview your changes before they are actually written to disk, there are a few ways of accomplishing this, but the simpliest is probably to modify the command as follows:
find . -name "*.html" -exec sed "s/foo/bar/g" '{}' \; | less
Removing the "-i" will mean that instead of writing the changes "in place", the changed output will be written to STDOUT instead of the files.
Then to capture this (potentially large) output, we pipe it to less.
From within less you will be able to do searches (with the "/" key) and scroll through the output to do a quick sanity check.
Once your happy, you can remove the pipe and add the "-i" option again to make it permanent!
2 comments:
That would be very useful if I used Linux more... instead I fight the Windows tools ;)
p.s. [.] looks funny, I thought \. would work, but it looks like you have to use \\. -- and that looks really ugly and is the same amount of chars anyway!
lol, yea, I set up all the linux tools with cygwin in windows when I was forced to use it at my old work, but these things seem lot easier for me in linux!
Re: the regex, you could just use \. and you shouldn't need to escape the backslash.
Infact that's what I had first, but I changed it to the square brackets at the last minute.
I thought escaping the dots and the | character made it look a bit more complicated - too many backslashes, even though it was lass characters.
".*\.html\|.*\.js"
".*[.]html\|.*[.]js"
It's all the same really, just trying to make the blog as easy to read as possible for my millions of fans ;)
...jokes
Post a Comment