Effective editing of multiple files in Vim
This post will cover a couple of commands which are very useful when you’re editing multiple files at once. For each type of list in Vim, there’s an appropriate command which gives us the possibility to execute commands in bulk. Here they are:
:argdo- for argument list
:bufdo- for buffer list
:windo- for window list
We will also cover two more commands which you’ll use often when editing multiple files:
:norm[al]- for running commands in Normal mode
:exe[cute]- for executing commands
## The execute and normal commands
The execute command
exe[cute] command is used to evaluate a string as if it’s a Vim command. You could run a command like this:
:execute "echom 'Hello world!'" to echo the string
Hello world. In this example, we used internal Vim command for echoing content
This command is a very handy tool, because it lets you create commands out of an arbitrary string.
The normal command
If you try running the command
:normal gg you’ll see that your cursor will jump to the first line in your current buffer.
As you might guess already,
norm[al] command simply takes a sequence of keys you’ve typed and treats them as a Vim command you would enter in Normal mode.
Of course, this command will pick up your personal mappings if they exist. That brings us to the next question: what happens if a user has remapped
gg command to delete one line, instead of jumping to first line of the buffer?
In that case, the example from above will execute the command for deleting the line, or whatever else was specified for the mapping.
But, even if there were a mapping for
gg command, which is different than default action of jumping to the first line, you can still use the default mapping of the command. Here’s how:
This way, Vim will move your cursor to the first line of a buffer, even if there’s already a different mapping for
gg sequence of keys. So if you use
!, mappings will not be used.
You can also use ranges to execute Normal mode commands for each line in the specified range.
For more details on this command, take a look at
## argdo vs bufdo
Pay attention here, and make sure to understand the difference between
:bufdo, because this is unclear even to some advanced Vim users.
As you already learned, Vim has different types of lists for different purposes. Another very important list is the so called “arguments list.” This list holds the files which you specify when you start Vim. We’ll call it arglist from now on.
For example, if you start Vim like this:
$ vim my_file1.txt my_file2.txt
Vim will add to arglist two items (
my_file2.txt). Once you’re in Vim, you could show the contents of arglist by running
Now, when you open these two files, Vim creates two buffers, for each of the files. As we mentioned before, you can show the buffers list by running
At this point, both lists, for arguments and buffers, contain items
If we additionally, from Vim, open another file like
Vim will create one more buffer for this file. It will also add another item in buffers list. So now, the buffers list will contain three items (for all three files we’ve opened), while arglist will still contain two items (with
And here we finally come to the point:
argdocommand affects only the files present in arglist.
bufdocommand affects only the files present in buffers list.
In our example, editing files via
argdo command would affect only
bufdo command would affect these two, plus
Now let’s take a look as some useful examples of these commands.
## bufdo examples
When you open a file in Vim, you’ve actually created a Vim buffer, as we already said. For each new file you open, its buffer is added to the internal buffers list.
Let’s say you have opened multiple files, so you have multiple buffers. At one point, you want to execute a command which will affect all the active buffers (in buffers list), you need to use
For example, it’s the end of your work day, you want to save your work and go home. You’ve already edited multiple buffers, but you didn’t save your changes. Of course you shouldn’t switch from buffer to buffer and run
:wq. In order to save changes in all your active buffers and exit Vim, simply run
This way, we’ve just told Vim to execute
:wq command in each active buffer. Alternatively, you could also run the command
:wqa which will write changes in all buffers and quit Vim.
Paste to the end of each buffer
:bufdo exe ":normal Gp" | update
Let’s break it down:
:bufdo- execute commands over all active buffers
exe- the “execute” command, which will execute the command between double quotes.
":normal Gp"- this will be executed by
execommand. We use
:normal Gpto tell Vim: run
G(jump to the end of a file) and
p(paste) in Normal mode.
| update- when the previous commands are executed, we use
|to execute another command (
update), which actually writes the changes in the buffers. You could also use
Related tip: Whenever you execute :w, Vim will actually write the buffer to the file, no matter whether the buffer was changed from the last saved state. This means it will update the timestamp of the file to the time when you run :w, even if the contents of the file did not actually change.
On the other hand, when you execute :up[date], the Vim will update the file timestamp ONLY if the file has been changed.
Executing macro over all active buffers
:bufdo execute "normal! @a" | w
As you can see, the structure of the command is the same as in the previous example. This time we run
@a command in Normal mode to execute the macro recorded in register
a. Also, this time we use
w instead of
update (for no specific reason).
We have already covered how to manage buffers in chapter Buffers, so we won’t repeat the commands for adding and deleting buffers.
## argdo examples
All of the examples for
:bufdo command can be applied to files stored in arglist, by replacing
Before we get to some examples, it’s important to mention that we can, just like with buffers list, add and delete items in arglist.
Here are a few useful commands:
||Show files in your current arglist|
||Replace old arglist files with new ones|
||Remove files from your arglist|
||Save changes to all arglist files|
||Undo last operation in each arglist file|
Here’s an example: You’re working on a project, and have multiple files in your
git branch. You want to replace string
Bad with string
Good across the entire project.
We can do this in two steps, here’s the first one:
:args `git grep -l Bad`
This command runs a shell command
git grep -l Bad, which will provide us the list of files containing string
Bad, and place those files in argslist.
Then, we can run:
:argdo %s/Bad/Good/gc | update
and perform the substitution across all files in arglist, and save the changes.
But, what if you add multiple files to the arglist, and you want to replace
good in all of them where
bad appears, without using external shell commands? If you would run a command like this:
:argdo %s/bad/good/g | update
Vim will say there’s an error when the search operation fails for a file which doesn’t contain the string
bad. This will prevent completing the substitution over all files in the arglist. A better way to run this command would be:
:argdo %s/bad/good/ge | update
We have included
e flag, which tells Vim to not issue an error if the search for the pattern fails. If you’d like to perform substitution selectively, and skip some of the matches, you could just add the
One last example will show you how you can use shell commands from Vim.
:argdo exe '%!sort' | w
This command will sort the contents of all files in your arglist. It calls the shell command
## windo command
Let’s keep it short.
:windo is similar to
:bufdo, with one important difference: it only affects the visible buffers. As we already mentioned, Vim can have many buffers open, but if there’s only one window, then only one buffer is shown at the time.
So, if you have a Vim session with multiple windows open, then the commands you run with
:windo will be applied only to those buffers which are currently visible in your windows.
Let’s summarize. There’s so much power in these commands. We’ve covered the most important concepts and some real word examples. Take time to understand and learn how you can use these commands, and very quickly you’ll become very effective at editing multiple files.
You're welcome to join my private email list or follow me on Twitter.