Wandering Thoughts archives

2019-10-03

Making changes to multiple files at once in Vim

We recently finished switching the last of our machines to a different client for Let's Encrypt, and as part of that switch the paths to our TLS certificates had to be updated in all of the configuration files using them. On a lot of our machines there's only a single configuration file, but on some of our Apache servers we have TLS certificate paths in multiple files. This made me quite interested in finding out how to do the same change across multiple files in Vim. It turns out that Vim has supported this for a long time and you can go about it in a variety of ways. Some of these ways expose what I would call a quirk of Vim and other people probably call long-standing design decisions.

Under most circumstances, or more specifically when I'm editing only a moderate number of files, the easiest thing for me to do is to use the very convenient ':all' command to open a window for every buffer, and then use ':windo' to apply a command for every window, eg ':windo %s/.../.../'. Then I'd write out all of the changed buffers with ':wa'.

The Vim tips on Search and replace in multiple buffers and Run a command in multiple buffers also cover ':bufdo', which runs things on all buffers whether or not they're in windows. That was in fact the first thing I tried, except I left off the magic bit to write out changed buffers and Vim promptly stopped after making my change in the first file. This is what I consider a historical quirk, although we're stuck with it.

Vi has long had multiple buffers, but it's always been pretty stubborn about getting you to write out your changes to the current buffer before you moved to another one. It's easy to see the attraction of getting people to do this on the small and relatively loaded machines that vi was originally written on, since a clean buffer is a buffer that you don't have to retain in memory or in a scratch file on disk (and it's also not at risk if either vi or the machine crashes). However, these days it's at odds with how most other multi-file editors approach the problem. Most of them will let you keep any number of modified buffers around without complaint, and merely stop you from quitting without saving them or actively discarding them. Not hassling you all of the time makes these editors a bit easier to use, and Vim is already a bit inconsistent here since windows are allowed to be changed without preventing you from switching away from them.

Given my views here, I probably want to set 'hidden' to on. Unless I'm very confident in my change, I don't want to add '| update' to the ':bufdo' command to immediately write out updates, and as noted 'hidden' being on makes Vim behave more like other editors. The drawbacks that the Vim documentation notes don't apply to me; I never use ':q!' or ':qa!' unless my intention is explicitly to discard all unsaved changes.

It's possible to do this in a trickier way, with the ':hide' command. Because I just experimented with this, it should be done as:

:hide bufdo %s/.../.../

I don't think there's a perfect way to undo the effects of a multi-file operation that didn't work out as I intended. If all buffers were unchanged before the bufdo or windo, I can use it again to invoke undo in each buffer, with ':bufdo u'. With unchanged buffers, this is harmless if my cross-file operation didn't actually change a particular file. If there are unsaved changes in some buffers, though, this becomes dangerous because the undo in each buffer is blind; it will undo the most recent change whether or not that came from the first 'bufdo'.

(All of this tells me that I should carefully (re)read the Vim buffer FAQ, because how Vim does buffers, files, tabs, and windows is kind of confusing. GNU Emacs is also confusing here in its own way, but at least with it I understand the history.)

On the whole, ':all' and then ':windo ...' is the easier to remember and easier to use option, and it lets me immediately inspect some of the changes across all of the files involved. So it's likely to be what I normally use. It's not as elegant as the various other options and I'm sure that Vim purists will sigh, but I'm very much not a Vim purist.

(This is one of those entries that I write for my own future reference. Someday I'll write a page in CSpace to collect all of the Vim things that I want to remember and keep using regularly, but for now blog entries will have to do.)

unix/VimMultiFileChanges written at 23:54:31; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.