Search

The Only Mac I Use

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 a Tech Editor and columnist at Linux Journal and the Chief Security Officer at Purism. He is the author of Linux Hardening in Hostile Networks, DevOps Troubleshooting, The Official Ubuntu Server Book, Knoppix Hacks, Knoppix Pocket Reference, Linux Multimedia
Hacks and Ubuntu Hacks, and also a contributor to a number of other O'Reilly books. Rankin speaks frequently on security and open-source software including at
BsidesLV, O'Reilly Security Conference, OSCON, SCALE, CactusCon, Linux World Expo and Penguicon. You can follow him at @kylerankin.