JohnBeckett (talk | contribs) (more tweaks) |
Tag: Visual edit |
||
(6 intermediate revisions by 5 users not shown) | |||
Line 11: | Line 11: | ||
|category2= |
|category2= |
||
}} |
}} |
||
− | Often [[search and replace]] is needed in multiple files. This tip uses the procedures from [[run a command in multiple buffers]] to show how a substitute may be executed multiple times using < |
+ | Often [[search and replace]] is needed in multiple files. This tip uses the procedures from [[run a command in multiple buffers]] to show how a substitute may be executed multiple times using <code>:argdo</code> (all files in argument list), or <code>:bufdo</code> (all buffers), or <code>:tabdo</code> (all tabs), <code>:windo</code> (all windows in the current tab), or <code>:cdo</code> (all files listed in the quickfix list). |
==All buffers== |
==All buffers== |
||
− | The following performs a search and replace in all buffers (all those listed with the < |
+ | The following performs a search and replace in all buffers (all those listed with the <code>:ls</code> command): |
<pre> |
<pre> |
||
:bufdo %s/pattern/replace/ge | update |
:bufdo %s/pattern/replace/ge | update |
||
Line 20: | Line 20: | ||
{| class="cleartable" |
{| class="cleartable" |
||
− | |< |
+ | |<code>bufdo</code> || Apply the following commands to all buffers. |
|- |
|- |
||
− | |< |
+ | |<code>%s</code> || Search and replace all lines in the buffer. |
|- |
|- |
||
− | |< |
+ | |<code>pattern</code> || Search [[Search patterns|pattern]]. |
|- |
|- |
||
− | |< |
+ | |<code>replace</code> || Replacement text. |
|- |
|- |
||
− | |< |
+ | |<code>g</code> || Change all occurrences in each line (global). |
|- |
|- |
||
− | |< |
+ | |<code>e</code> || No error if the pattern is not found. |
|- |
|- |
||
− | |< |
+ | |<code>|</code> || Separator between commands. |
|- |
|- |
||
− | |< |
+ | |<code>update</code> || Save (write file only if changes were made). |
|} |
|} |
||
− | The command above uses < |
+ | The command above uses <code>:update</code> to save each buffer, if it was changed. That is necessary because, by default, Vim will not switch away from a buffer if it has been changed. |
− | One alternative is to set the < |
+ | One alternative is to set the <code>'autowriteall'</code> option so changed buffers are automatically saved when required: |
<pre> |
<pre> |
||
:set autowriteall |
:set autowriteall |
||
Line 45: | Line 45: | ||
</pre> |
</pre> |
||
− | Another alternative is to set the < |
+ | Another alternative is to set the <code>'hidden'</code> option so buffers do not need to be saved, then use <code>:wa</code> to save all changes (only changed buffers are written): |
<pre> |
<pre> |
||
:set hidden |
:set hidden |
||
Line 51: | Line 51: | ||
:wa |
:wa |
||
</pre> |
</pre> |
||
+ | |||
+ | If you don't wish to save the results of your replacement, but want to review each changed buffer first, you can force the bufdo to continue without saving files with <code>bufdo!</code>: |
||
+ | |||
+ | <pre> |
||
+ | :bufdo! %s/pattern/replace/ge |
||
+ | </pre> |
||
+ | |||
+ | ==All windows== |
||
+ | If you are not dealing with a lot of files, it can be useful to display each wanted file in its own window, then operate on each window. For example, after opening multiple files with a shell command like <code>gvim *.c</code>, you could choose which files you wanted to operate on like this: |
||
+ | {| class="cleartable" |
||
+ | |<code>:sball</code> || Split screen to show all buffers (one window per buffer). |
||
+ | |- |
||
+ | |... || Move to a window you do ''not'' want to change. |
||
+ | |- |
||
+ | |<code><C-w>c</code> || Close the window (press Ctrl-W then <code>c</code>). |
||
+ | |- |
||
+ | |<code><C-w>T<C-PageUp></code> || Or, move the window to a new tab page, then switch back to the original tab. |
||
+ | |- |
||
+ | |... || Repeat until only buffers you want to change are displayed in the current tab page. |
||
+ | |- |
||
+ | |style="white-space:nowrap" | <code>:windo %s/pattern/replace/ge</code> || Search and replace in all visible windows. |
||
+ | |- |
||
+ | |<code>:wa</code> || Save all changes. |
||
+ | |} |
||
+ | |||
+ | ==All files in a tree== |
||
+ | Suppose all *.cpp and *.h files in the current directory need to be changed (not subdirectories). One approach is to use the argument list (arglist): |
||
+ | {| class="cleartable" |
||
+ | |<code>:arg *.cpp</code> || All *.cpp files in current directory. |
||
+ | |- |
||
+ | |<code>:argadd *.h</code> || And all *.h files. |
||
+ | |- |
||
+ | |<code>:arg</code> || ''Optional'': Display the current arglist. |
||
+ | |- |
||
+ | |style="white-space:nowrap" | <code>:argdo %s/pattern/replace/ge | update</code> || Search and replace in all files in arglist. |
||
+ | |} |
||
+ | |||
+ | A similar procedure can perform the same operation on all wanted files in the current directory, and in all subdirectories (or in any specified tree of directories): |
||
+ | {| class="cleartable" |
||
+ | |<code>:arg **/*.cpp</code> || All *.cpp files in and below current directory. |
||
+ | |- |
||
+ | |<code>:argadd **/*.h</code> || And all *.h files. |
||
+ | |- |
||
+ | |<code>...</code> || As above, use <code>:arg</code> to list files, or <code>:argdo</code> to change. |
||
+ | |} |
||
+ | |||
+ | In the above, a forward slash was used in <code>**/*.cpp</code>. That works on all systems (Unix and Windows). If wanted, a backslash can be used on Windows systems. |
||
==Replacing current word== |
==Replacing current word== |
||
A common requirement is to replace the word under the cursor in a number of files. Rather than automating the process, it is best to use Vim's procedures. For example: |
A common requirement is to replace the word under the cursor in a number of files. Rather than automating the process, it is best to use Vim's procedures. For example: |
||
{| class="cleartable" |
{| class="cleartable" |
||
− | |< |
+ | |<code>:arg *.cpp</code> || All *.cpp files in directory. |
|- |
|- |
||
− | |< |
+ | |<code>:argadd *.h</code> || And all *.h files. |
|- |
|- |
||
|... || Move cursor to word that is to be replaced. |
|... || Move cursor to word that is to be replaced. |
||
|- |
|- |
||
− | |< |
+ | |<code>*</code> || Search for that exact word. |
|- |
|- |
||
− | |< |
+ | |style="white-space:nowrap" | <code>:argdo %s//replace/ge | update</code> || Search and replace in all files in arglist. |
|} |
|} |
||
In the above substitute command: |
In the above substitute command: |
||
*The search pattern is empty, so the last search is used. |
*The search pattern is empty, so the last search is used. |
||
− | *Type your replacement text instead of < |
+ | *Type your replacement text instead of <code>replace</code>. If the text is similar to the current word press Ctrl-R then Ctrl-W to insert that word into the command line, then change it. |
Alternatively, you might try the following user command or mapping. |
Alternatively, you might try the following user command or mapping. |
||
Line 88: | Line 135: | ||
For example: |
For example: |
||
{| class="cleartable" |
{| class="cleartable" |
||
− | |< |
+ | |<code>:arg *.c</code> || All *.c files in current directory. |
|- |
|- |
||
− | |< |
+ | |<code>:set hidden</code> || Allow switching away from a changed buffer without saving. |
|- |
|- |
||
− | |< |
+ | |<code>:set autowriteall</code> || Or, use this for automatic saving (instead of <code>:set hidden</code>). |
|- |
|- |
||
|... || Move cursor to word that is to be replaced. |
|... || Move cursor to word that is to be replaced. |
||
|- |
|- |
||
− | |< |
+ | |<code>:Replace whatever</code> || Search and replace in all files in arglist; confirm each change. |
|- |
|- |
||
− | |< |
+ | |<code>:Replace! whatever</code> || Same, but do not confirm each change. |
|- |
|- |
||
− | |< |
+ | |<code>:wa</code> || Write all changed files (not needed if used <code>:set autowriteall</code>). |
|} |
|} |
||
− | Instead of the < |
+ | Instead of the <code>:Replace</code> command, you could use the mapping. Move the cursor to the word that is to be replaced and press <code>\r</code> (backslash, assuming the default Leader key, then <code>r</code>). |
− | In the function, any special characters in the search word are escaped for generality, although that is unlikely to be needed since a word will not contain special characters. If the cursor is on the word < |
+ | In the function, any special characters in the search word are escaped for generality, although that is unlikely to be needed since a word will not contain special characters. If the cursor is on the word <code>old_text</code>, the search pattern will be <code>\<old_text\></code> so that only instances of the whole word are found. |
==Comments== |
==Comments== |
||
+ | Thank you so much. It was very very helpful and saved so much of my time. |
||
+ | |||
+ | Ditto! This is so much easier than using sed. |
Revision as of 18:28, 13 March 2020
Often search and replace is needed in multiple files. This tip uses the procedures from run a command in multiple buffers to show how a substitute may be executed multiple times using :argdo
(all files in argument list), or :bufdo
(all buffers), or :tabdo
(all tabs), :windo
(all windows in the current tab), or :cdo
(all files listed in the quickfix list).
All buffers
The following performs a search and replace in all buffers (all those listed with the :ls
command):
:bufdo %s/pattern/replace/ge | update
bufdo |
Apply the following commands to all buffers. |
%s |
Search and replace all lines in the buffer. |
pattern |
Search pattern. |
replace |
Replacement text. |
g |
Change all occurrences in each line (global). |
e |
No error if the pattern is not found. |
| |
Separator between commands. |
update |
Save (write file only if changes were made). |
The command above uses :update
to save each buffer, if it was changed. That is necessary because, by default, Vim will not switch away from a buffer if it has been changed.
One alternative is to set the 'autowriteall'
option so changed buffers are automatically saved when required:
:set autowriteall :bufdo %s/pattern/replace/ge
Another alternative is to set the 'hidden'
option so buffers do not need to be saved, then use :wa
to save all changes (only changed buffers are written):
:set hidden :bufdo %s/pattern/replace/ge :wa
If you don't wish to save the results of your replacement, but want to review each changed buffer first, you can force the bufdo to continue without saving files with bufdo!
:
:bufdo! %s/pattern/replace/ge
All windows
If you are not dealing with a lot of files, it can be useful to display each wanted file in its own window, then operate on each window. For example, after opening multiple files with a shell command like gvim *.c
, you could choose which files you wanted to operate on like this:
:sball |
Split screen to show all buffers (one window per buffer). |
... | Move to a window you do not want to change. |
<C-w>c |
Close the window (press Ctrl-W then c ).
|
<C-w>T<C-PageUp> |
Or, move the window to a new tab page, then switch back to the original tab. |
... | Repeat until only buffers you want to change are displayed in the current tab page. |
:windo %s/pattern/replace/ge |
Search and replace in all visible windows. |
:wa |
Save all changes. |
All files in a tree
Suppose all *.cpp and *.h files in the current directory need to be changed (not subdirectories). One approach is to use the argument list (arglist):
:arg *.cpp |
All *.cpp files in current directory. |
:argadd *.h |
And all *.h files. |
:arg |
Optional: Display the current arglist. |
:argdo %s/pattern/replace/ge | update |
Search and replace in all files in arglist. |
A similar procedure can perform the same operation on all wanted files in the current directory, and in all subdirectories (or in any specified tree of directories):
:arg **/*.cpp |
All *.cpp files in and below current directory. |
:argadd **/*.h |
And all *.h files. |
... |
As above, use :arg to list files, or :argdo to change.
|
In the above, a forward slash was used in **/*.cpp
. That works on all systems (Unix and Windows). If wanted, a backslash can be used on Windows systems.
Replacing current word
A common requirement is to replace the word under the cursor in a number of files. Rather than automating the process, it is best to use Vim's procedures. For example:
:arg *.cpp |
All *.cpp files in directory. |
:argadd *.h |
And all *.h files. |
... | Move cursor to word that is to be replaced. |
* |
Search for that exact word. |
:argdo %s//replace/ge | update |
Search and replace in all files in arglist. |
In the above substitute command:
- The search pattern is empty, so the last search is used.
- Type your replacement text instead of
replace
. If the text is similar to the current word press Ctrl-R then Ctrl-W to insert that word into the command line, then change it.
Alternatively, you might try the following user command or mapping.
" Search for current word and replace with given text for files in arglist. function! Replace(bang, replace) let flag = 'ge' if !a:bang let flag .= 'c' endif let search = '\<' . escape(expand('<cword>'), '/\.*$^~[') . '\>' let replace = escape(a:replace, '/\&~') execute 'argdo %s/' . search . '/' . replace . '/' . flag endfunction command! -nargs=1 -bang Replace :call Replace(<bang>0, <q-args>) nnoremap <Leader>r :call Replace(0, input('Replace '.expand('<cword>').' with: '))<CR>
For example:
:arg *.c |
All *.c files in current directory. |
:set hidden |
Allow switching away from a changed buffer without saving. |
:set autowriteall |
Or, use this for automatic saving (instead of :set hidden ).
|
... | Move cursor to word that is to be replaced. |
:Replace whatever |
Search and replace in all files in arglist; confirm each change. |
:Replace! whatever |
Same, but do not confirm each change. |
:wa |
Write all changed files (not needed if used :set autowriteall ).
|
Instead of the :Replace
command, you could use the mapping. Move the cursor to the word that is to be replaced and press \r
(backslash, assuming the default Leader key, then r
).
In the function, any special characters in the search word are escaped for generality, although that is unlikely to be needed since a word will not contain special characters. If the cursor is on the word old_text
, the search pattern will be \<old_text\>
so that only instances of the whole word are found.
Comments
Thank you so much. It was very very helpful and saved so much of my time.
Ditto! This is so much easier than using sed.