Vim Tips Wiki
Advertisement
Tip 373 Printable Monobook Previous Next

created 2002 · complexity basic · author David Fishburn · version 6.0


I wanted to recursively edit all html files in a folder/subfolders and run a search and replace command (substitute) in each one, then save the files when finished.

Following is what my batch (WinXP) file does. Note, since this is running in a windows batch/command file, I had to escape the % sign (use '%%' to represent a single '%').

First start a new instance of gvim, so it doesn't use one that I am already using. Give it a specific name so the commands are contained to it.

start gvim --servername BEAD

Using the FOR statement recursively edit all htm files and send them to the gvim session I just started:

FOR /R %%i IN (*.htm) DO gvim --servername BEAD --remote-silent "%%i"

Now, send the bufdo command to that server that will run a substitute command. I also used the ge options so that no error was reported if the search string was not found.

gvim --servername BEAD --remote-send "<Esc>:bufdo %%s/Tweety Bird/Road Runner/ge<CR>"

Now save all files and exit

gvim --servername BEAD --remote-send "<Esc>:xall<CR>"

The batch file is:

start gvim --servername BEAD
FOR /R %%i IN (*.htm) DO gvim --servername BEAD --remote-silent "%%i"
gvim --servername BEAD --remote-send "<Esc>:bufdo %%s/Tweety Bird/Road
Runner/ge<CR>"
gvim --servername BEAD --remote-send "<Esc>:bufdo
%%s/\(^File:.*JPG\).*/\1/ge<CR>"
rem Write all files and exit
gvim --servername BEAD --remote-send "<Esc>:xall<CR>"

See also

Comments

See :args and :argdo.


How to use :args to search recursive in subdirectories?

Use something like this:

:args *.cpp */*.cpp */*/*.cpp

Not exactly recursive, but works well for reasonably flat directory hierarchies.


Fantastic Tip. Saved me a lot of time. I had to put the [ ! ] after the bufdo command so it would move on to the next buffer.

gvim --servername BEAD --remote-send "<Esc>:bufdo! %%s/Tweety Bird/Road Runner/ge<CR>"

Using Windows XP it caused some weird problems. I solved it by running gvim using start every time, like the first time. I also added some sleep statements, but i'm not shure if it's neccesary.


If you have some hudreds of files, this is simple unusable.

You have to watch it showing "pattern not found" for dozens of files, wich will make it hang when it uses the entire screen until you press space.


In a *nix shel, as found on http://www.jesus.com.au/html/page/vim :

for i in `find . -name '*.txt'`; do vim -c "%s/nonsenes/nonsense/g | w | q" "$i"; done

Obviously, do NOT execute that exact command, or anything like it, unless you know what you're doing.


Not if you add '!' as in bufdo!, then it will not prompt for keypress when screen fills.


The FOR statement is very slow.


Works fine. I changed a bit to accommodate for my needings:

set gvim=c:\Arquivos de programas\Vim\vim72\gvim.exe
set filemask=`dir /s /w /b D:\projetos\PertoEmulatorTest\*.vcproj`
set searchpattern=\C\^<PERTOAPI_8\^>
set replacepattern=PERTOAPI_VERSION=-2000
set gvimservername=BEAD

start "gvim" "%gvim%" --servername "%gvimservername%"
"%gvim%" --servername "%gvimservername%" --remote-send "<ESC>:set modifiable<CR>"
FOR /F "usebackq delims=" %%i IN (%filemask%) DO "%gvim%" --servername "%gvimservername%" --remote-silent "%%i"
"%gvim%" --servername "%gvimservername%" --remote-send "<Esc>:bufdo! %%s/%searchpattern%/%replacepattern%/ge<CR>"
rem "%gvim%" --servername "%gvimservername%" --remote-send "<Esc>:bufdo! %%s/\(^File:.*JPG\).*/\1/ge<CR>"
rem Write all files and exit
"%gvim%" --servername "%gvimservername%" --remote-send "<Esc>:xall<CR>"

The `for' now use `/f' with `usebackq' to evaluate a dir command (the `filemask' variable) and an empty `delims' to allow file paths with spaces. The `set modifiable' was necessary due to the fact that `.vimrc' has `set nomodifiable'.


I needed an *interactive* search and replace for multiple files.

Here is a quick *nix bash script that accomplishes the task:

#!/bin/bash
# Script name: vim-command
#
# Applies a vim command to all input files.
#
# The vim command is requested interactively, and is equivalent to running vim
# with the -c option (see the vim manual).
#
# Useful for interactive search/replace, etc.
#
# Example:
# vim-command `grep -lr --include='*.php' Rest ./`
#
# Recursively runs vim on all files with a '.php' extension containing the
# word "Rest", starting in the current directory.
# The command string used in this example was :%s/Rest/Http/gc

# Set the command string
echo;
echo 'Please enter your command string below.';
printf '> ';
read;
COMMAND=$REPLY;

# Execute the command on all the given files
for FILE_NAME in "$@"
do
    # run the command on each file sequentially
    vim -c "$COMMAND" $FILE_NAME;
    echo "Done: $FILE_NAME";
done

The command-line session looked like so:

$ vim-command `grep -lr --include='*.php' Rest ./`

Please enter your command string below.
> :%s/Rest/Http/gc
Done: ./tmp.php
$

This page is kind of all over the place, but as far as I can tell, the following is the quickest way to do one thing to a lot of files using vim from the command line:

vim -Ec 'exe "bufdo se ff=unix"|xa' **/*.php

-E

ex-mode (otherwise vim will needlessly start up curses)

-c

Run the following command

exe[c]

Encapsulate the bufdo since it would otherwise think the | was part of its arguments

bufdo

Run the following command on every buffer

se[t] f[ile]f[ormat]=unix

This fixes the line-ending format. But you can replace it with your own command.

|xa

After that, save all buffers and quit

**/*.php

The files

--Holizz 21:40, May 2, 2011 (UTC)

Advertisement