Executing a Command in Multiple Files in Vim

June 3, 2021

Executing a Command in Multiple Files in Vim

When editing, you may need to execute a command across multiple files. For example, replacing all let with const.

There are eight different ways you can do this in Vim.

:argdo    argument list (files)
:bufdo    buffers
:windo    windows in the current tab
:tabdo    tabs
:cdo      each item in the quickfix list
:cfdo     each file in the quickfix list
:ldo      each item in the location list
:lfdo     each file in the location list

Eight sounds like a lot of methods learn at once. However, the principle behind all of them is the same: make a list of what you want to change, then run the command to the entire member of that group, then save. The only difference is the scope of each entry.

Let's go over two of them here. Once you get a feeling how it works, using any of the methods above is just a matter of syntactical differences.

Argument List

The argument list (argdo) uses file as the scope. To create an argument list consisting of file1.txt, file2.txt, and file3.txt, run :args file1.txt file2.txt file3.txt (you can also use the blob operator: run :args *txt to collect all txt files in the current directory, run :args **txt to collect all txt files recursively, run :args z*txt to collect all txt files in the current directory that starts with "z").

To check that you have the correct files, run :args. On the bottom screen, you should see something like [file1.txt] file2.txt file3.txt, indicating that you are currently on file1.txt. You can move around the argument list with :next, :prev, :first, :last, etc. Make sure that you are on the first entry before running the command.

Now run :argdo %s/kale/pancake/g | update. That's it. All kales inside file1.txt, file2.txt, and file3.txt are now substituted with pancakes. Sweet!

Command breakdown:

  • :argdo performs the given command on all entry in the argument list.
  • :%s/kale/pancake/g is the substitute command.
  • | lets you to chain multiple commands together.
  • update saves each file.

Quickfix List

Next, let's go over the quickfix list. If you not familiar, quickfix is Vim's special mode originally created to handle edit-compile-edit cycle error messages, but eventually evolved and used for all sorts of other things from displaying STDOUT when running async operations in vim-dispatch, fuzzy searching in fzf.vim, etc. For our purpose, think of it as a list of pointers to various location in your files.

Some commands in Vim automatically uses quickfix, like :make, :grep, and :vimgrep.

If you need to list all occurrences of "veggies" inside any text file, run :vimgrep /veggies/ **txt. To see the quickfix matches, run :copen (quickfix open). To apply the substitute command to all quickfix matches, run :cfdo %s/kale/pancake/g | update. That's it. It follows a similar pattern like the argument list: collect-apply-save.

You can move around in a quickfix list with :cfirst, :clast, :cnext, :cprev, etc.

If you notice, on the list above you'll see cfdo and cdo quickfix operations. What's the difference? The difference is that cfdo is a per-file operator and cdo is a per-match operator. cfdo will run the command once per file and cdo will run the command once per match.

If you have 5 matches for "veggies" inside file1.txt, running :cfdo %s/kale/pancake/g will run the command once while running :cdo %s/kale/pancake/g will run the command 5 times.

Since we are running a file-wide command (%s), it makes sense to run it only once per file.

Conclusion

Vim's multi-file operations are useful to apply a change across multiple files. There are eight different ways to accomplish this, although the underlying principle is the same: collect-apply-save. Play around with the args / argdo and vimgrep / cfdo combos. Once you get comfortable with them, play around with the other commands.

Happy Vimming!

Shameless disclaimer: if you enjoy this, there's a 98.39% (not scientifically proven) you will also enjoy my Vim Cookbook: Gourmet Vim. Check it out!