The Only Mac I Use

 in

Mac? Only if it's a vim macro.

Okay, so the title is a bit of a troll. Although people are, of course, free to use whatever computers they want, I've personally never liked Macs. I've always found it strange how many Linux advocates rail against Microsoft, but hold their tongues when Apple does the same things. In any case, this isn't an article about that—it's actually about vim macros, because a vim macro is about as close as I'll get to a Mac—or Emacs, for that matter. Hey, that makes two holy wars in the first paragraph—not bad.

It's no secret to frequent readers of my column that I use vim as my editor. I've even written a series of columns in the past about applications that use vi-style key bindings for navigation. In this article though, I'm going to highlight one of my favorite time-saving features of vim since I discovered you could use Ctrl-[ instead of Esc: macros.

Like with a lot of things I've learned through the years, it took having an almost insurmountable problem for me to learn how to use vim macros effectively and commit the vim macro syntax to memory. Quite a few years ago, I was an administrator for a DNS system that served thousands of zones. We were in the middle of a project to migrate to a new data center, so that meant that tens of changes needed to be made to thousands of DNS zone files to point them to the new site. Fortunately, we had time to stage the changes so this wasn't an all-or-nothing endeavor. The trick though was that the zone files had been created through the years by different administrators who each had their own sense of style. This meant I couldn't just write a script to do generic search and replace for me. Beyond that, the stakes were high enough that I couldn't afford a bug in a script wreaking subtle, silent destruction on zone files.

At first, I just hit this massive assignment head-on, by hand, and we decided on 20-zone batches. I'd open a zone file in vim, make my changes and then save them. What I noticed after a few rounds of this was that in many cases I was doing the same exact keystrokes in the files. I'd go to the top of the file, update the serial number, then perform a few basic search-and-replace commands on some IPs and on some record names. Although all the zones weren't uniform, I discovered that there were only maybe three or four different variations on my commands. At this point, I decided to research how to use vim macros and discovered I could save only a handful of macros and reduce my editing time from 30 seconds or a minute per zone file with many keystrokes to a few seconds and only a few keystrokes.

Essentially, a vim macro allows you to record keystrokes, assign them to a particular key on the keyboard, and then play them back one or more times later. If you already are efficient with your vim keystrokes (and by that I mean reducing your reliance on hjkl for navigation and using things like ^ and $ to go to the beginning and end of a line, w and b to skip forward and backward a word and searching for words to move to them), once you realize you are making a lot of repetitive keystrokes to edit a file, you'll know it's time to record a quick macro and save yourself time.

Personally, I've found macros particularly useful when editing DNS zone files because in the past I've needed to add, say, 50–100 new A records to a zone, with the only difference being that the hostname and IP address kept incrementing by one. It's this kind of problem I'm going to use as an example here to show you how to use macros. Let's say you have a zone file and need to add 50 A records starting with worker1 pointing to 10.9.0.15 and ultimately ending with worker50 pointing to 10.9.0.64. By hand, this is the kind of mundane task that would drive you crazy and burn an hour, but with vim macros, it takes only a few seconds.

The great thing about this particular problem that makes it well suited for vim macros is the fact that each line simply copies the previous line and increments two numbers. First, edit the file and add the first line by hand:


worker1  IN A  10.9.0.15

If you were to add the worker2 record, you might go one of two ways about it. Although you could just type everything by hand, you probably would type yyp to yank the worker1 line and paste it below. Next you might press e to go to the end of worker1 word, press r2 to replace the 1 with a 2, then type $ to go to the end of the line and type r6 to replace the 5 with a 6. That works, but it's difficult to repeat over and over, because the number changes each time. A better approach is to type yyp to copy and paste the worker1 line, and because the cursor is now over the worker1 word on the second line, press Ctrl-a, which in vim increments a number. Then, type $ to go to the end of the line and type Ctrl-a again to increment the 15 to a 16.

This approach that uses Ctrl-a is how you will tackle the macro. So with only the single worker1 line present and your cursor anywhere on that line, type q to trigger macro recording mode. Then press a key you want to assign this macro to, such as the a key. Your vim screen now will say the word recording in the bottom-left corner. Now that you are in recording mode, any keystrokes you make will be recorded until you press the q key again. Once in recording mode, type yyp to copy and paste the first line. The cursor is actually in a good position here at the beginning of the line, but if you aren't certain that an operation will always put your cursor in the right spot, it never hurts to throw in a ^ key to ensure that the cursor is at the beginning of the line. Next press Ctrl-a to increment worker1 so it becomes worker2. Now type $ to go to the end of the line, and press Ctrl-a again to increment the 15 to a 16. Finally, type q to exit recording mode.

Now you have a macro assigned to the a key. To replay your macro, make sure your cursor is now somewhere on the worker2 line, then press @a. The @ key tells vim to replay the macro assigned to whatever key you press next, in this case, a. You should see a third line below worker2 for the worker3 A record. This section of the file should now look like this:


worker1  IN A  10.9.0.15
worker2  IN A  10.9.0.16
worker3  IN A  10.9.0.17

Although you could just press @a 47 more times, vim allows you to preface just about any command with a number, and it will perform that command that many times. So, to finish up this file, make sure your cursor is somewhere on the worker3 line and press 47@a to see the remaining lines appear.

That's it. Now that you have a basic example of the power of macros, the next time you find yourself performing a repetitive task in a text file, see if you can assign it to a temporary macro. This article just scratches the surface of macros, so in a future column, I'll follow up with more macro tips including how and why to nest macros.

______________________

Kyle Rankin is senior security and infrastructure architect, the author of many books including Linux Hardening in Hostile Networks, DevOps Troubleshooting and The Official Ubuntu Server Book, and a columnist for Linux Journal. Follow him @kylerankin