Vim Tips Wiki
(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 <tt>:argdo</tt> (all files in argument list), or <tt>:bufdo</tt> (all buffers), or <tt>:tabdo</tt> (all tabs), or <tt>:windo</tt> (all windows in the current tab).
+
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 <tt>:ls</tt> command):
+
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"
|<tt>bufdo</tt> || Apply the following commands to all buffers.
+
|<code>bufdo</code> || Apply the following commands to all buffers.
 
|-
 
|-
|<tt>%s</tt> || Search and replace all lines in the buffer.
+
|<code>%s</code> || Search and replace all lines in the buffer.
 
|-
 
|-
|<tt>pattern</tt> || Search [[Search patterns|pattern]].
+
|<code>pattern</code> || Search [[Search patterns|pattern]].
 
|-
 
|-
|<tt>replace</tt> || Replacement text.
+
|<code>replace</code> || Replacement text.
 
|-
 
|-
|<tt>g</tt> || Change all occurrences in each line (global).
+
|<code>g</code> || Change all occurrences in each line (global).
 
|-
 
|-
|<tt>e</tt> || No error if the pattern is not found.
+
|<code>e</code> || No error if the pattern is not found.
 
|-
 
|-
|<tt>&#124;</tt> || Separator between commands.
+
|<code>&#124;</code> || Separator between commands.
 
|-
 
|-
|<tt>update</tt> || Save (write file only if changes were made).
+
|<code>update</code> || Save (write file only if changes were made).
 
|}
 
|}
   
The command above uses <tt>:update</tt> 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.
+
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 <tt>'autowriteall'</tt> option so changed buffers are automatically saved when required:
+
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 <tt>'hidden'</tt> option so buffers do not need to be saved, then use <tt>:wa</tt> to save all changes (only changed buffers are written):
+
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 &#124; 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"
|<tt>:arg **/*.cpp</tt> || All *.cpp files in and below current directory.
+
|<code>:arg *.cpp</code> || All *.cpp files in directory.
 
|-
 
|-
|<tt>:argadd **/*.h</tt> || And all *.h files.
+
|<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.
 
|-
 
|-
|<tt>*</tt> || Search for that exact word.
+
|<code>*</code> || Search for that exact word.
 
|-
 
|-
|<tt>:argdo %s//replace/ge &#124; update</tt> || Search and replace in all files in arglist.
+
|style="white-space:nowrap" | <code>:argdo %s//replace/ge &#124; 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 <tt>replace</tt>. 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.
+
*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"
|<tt>:arg *.c</tt> || All *.c files in current directory.
+
|<code>:arg *.c</code> || All *.c files in current directory.
 
|-
 
|-
|<tt>:set hidden</tt> || Allow switching away from a changed buffer without saving.
+
|<code>:set hidden</code> || Allow switching away from a changed buffer without saving.
 
|-
 
|-
|<tt>:set autowriteall</tt> || Or, use this for automatic saving (instead of <tt>:set hidden</tt>).
+
|<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.
 
|-
 
|-
|<tt>:Replace whatever</tt> || Search and replace in all files in arglist; confirm each change.
+
|<code>:Replace whatever</code> || Search and replace in all files in arglist; confirm each change.
 
|-
 
|-
|<tt>:Replace! whatever</tt> || Same, but do not confirm each change.
+
|<code>:Replace! whatever</code> || Same, but do not confirm each change.
 
|-
 
|-
|<tt>:wa</tt> || Write all changed files (not needed if used <tt>:set autowriteall</tt>).
+
|<code>:wa</code> || Write all changed files (not needed if used <code>:set autowriteall</code>).
 
|}
 
|}
   
Instead of the <tt>:Replace</tt> command, you could use the mapping. Move the cursor to the word that is to be replaced and press <tt>\r</tt> (backslash, assuming the default Leader key, then <tt>r</tt>).
+
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 <tt>old_text</tt>, the search pattern will be <tt>\<old_text\></tt> so that only instances of the whole word are found.
+
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

Tip 382 Printable Monobook Previous Next

created 2002 · complexity basic · version 6.0


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.