tags:

views:

108

answers:

4

I found out about Vim's substitute command...

:%s/replaceme/replacement/gi

And vimgrep...

:vimgrep  /findme/gj  project/**/*.rb

Is there a way to combine them in order to do a replacement across all the files under a dir?

+3  A: 

There's a plugin which endeavours to do just that: Vimgrep Replace.

Oh, wait... there are others: Global Replace, EasyGrep.

For a no plugin solution, perhaps argdo would help if you could get vimgrep's output onto the argument list (which can be set with args), but I can't seem to figure out the details. I'd be happy if somebody took the idea and improved upon it... so here it is.

The basic idea behind the first plugin (I'd guess the others too...) is to use vimgrep first, then cycle through the matches with :cnext and apply the substitution command on each line. A function to accomplish this could be small enough to put it in .vimrc. (Maybe you can lift one from the plugins' sources?)

(I suppose hgimenez might be on to a solution, but whether or not it's appropriate would probably depend on the number of files to be processed... The plugins should be ok regardless.)

Michał Marczyk
Ethan
@Ethan: I feel for you. :-) I think there must be a way involving :args, :argdo, :copen or whatever... I just don't use vimgrep enough to have thought much about it before and can't seem to be able to put together the perfect fix for you just yet. But I'm still trying, so perhaps I'll come up with something and edit.
Michał Marczyk
Michał Marczyk
If you really want to do it inside vim, just launch it with all the files you want on the command line, then use `bufdo` or `windo` as appropriate.
Jefromi
@Michal: Thanks, I guess it isn't really essential to do the operation within Vim.
Ethan
@Ethan: Too late, you got me curious... ;-) Good to know your problem's solved, though.
Michał Marczyk
+4  A: 

Even though I'm a Vim user, I generally use find and sed for this sort of thing. The regex syntax for sed is similar to Vim's (they're both descendants of ed), though not identical. With GNU sed you can also use -i for in-place edits (normally sed emits the modified version to stdout).

For example:

sed -i -e 's/replaceme/replacement/g' $(find project -name '*.rb')

Piece by piece:

  • run sed
  • with in-place edits
  • execute command...
  • ...substitute (alsmost the same as vim, but note lack of % -- it's the default in sed)
  • rest of args from find command:
    • find
    • in project tree
    • files whose names match...
    • ...'*.rb'
Laurence Gonsalves
Make sure and test your `find` before giving it to `sed` - this can be really bad if it's overly inclusive. It's also a good idea to give `sed` the `-c` (`--copy`) option, which will keep it from messing with read-only files.
Jefromi
+2  A: 

One way would be to open all the files you want to run the substitution on (or any command), and run :bufdo <cmd>, which will run <cmd> on all open buffers.

hgimenez
+2  A: 

You could run vimgrep then record a macro that goes to each line in the vimgrep output and does the replace, something like this: (dont type in the # comments!)

:set autowrite                  #automatically save the file when we change buffers
:vimgrep /pattern/ ./**/files  
qa                              #start recording macro in register a
:s/pattern/replace/g            #replace on the current line
:cnext                          #go to next matching line
q                               #stop recording
10000@a                          #repeat the macro 10000 times, or until stopped by 
                                #an "error" such as reaching the end of the list
:set noautowrite

I have not tested it, so it may need a little tweaking - test it on some files that you dont mind getting messed up first.

The advantage of this over sed is that Vim regex are more powerful, and you can add the c option to :s to verify each replacement.

Edit: I modified my original post since it was wrong. I was using :1vimgrep to find the first match in each file, but I misread the docs - it only finds one match across all files.

Dave Kirby
Cool! In searching for a single expression solution I never stopped to consider a macro... Makes me feel kind of silly now. +1. :-)
Michał Marczyk