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?
Basic Find and Replace In Vim, you can find and replace text using the :substitute ( :s ) command. To run commands in Vim, you must be in normal mode, the default mode when starting the editor. To go back to normal mode from any other mode, just press the 'Esc' key.
What is a recursive listing of files? Recursive means that Linux or Unix command works with the contains of directories, and if a directory has subdirectories and files, the command works on those files too (recursively).
Search for text using / or for a word using * . In normal mode, type cgn (change the next search hit) then immediately type the replacement. Press Esc to finish. From normal mode, search for the next occurrence that you want to replace ( n ) and press . to repeat the last change.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With