How can I search and replace recursively in a directory in Vim?

recursion, search, vim

Solution

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:

find project -name '*.rb' -type f -exec sed -i -e 's/regex/replacement/g' -- {} +

Piece by piece:

- `project` = search in "project" tree

- `-name '*.rb'` = for things whose names match '*.rb'

- `-type f` = and are regular files (not directories, pipes, symlinks, etc.)

- `-exec sed` = run `sed` with these arguments:

- `-i` = with in-place edits

- `-e 's/regex/replacement/g'` = execute a "substitute" command (which is almost identical to Vim's `:s`, but note lack of `%` -- it's the default in `sed`)

- `--` = end of flags, filenames start here

- `{}` = this tells `find` that the filenames it found should be placed on sed's command-line here

- `+` = this tells `find` that the `-exec` action is finished, and we want to group the arguments into as few `sed` invocations as possible (generally more efficient than running it once per filename). To run it once per filename you can use `\;` instead of `+`.

This is the general solution with GNU `sed` and `find`. This can be shortened a bit in special cases. For example, if you know that your name pattern will not match any directories you can leave out `-type f`. If you know that none of your files start with a `-` you can leave out `--`. Here's an answer I posted to another question with more details on passing filenames found with `find` to other commands.

Problem

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 directory?

Original source

Related problems