Text Objects & Macros
The course is part of this learning path
This course looks at text objects and macros in Vim, both of which are tools intended to help you edit text more quickly and efficiently. Text objects allow you to make changes to words, phrases, and sections of text based on various parameters. We then look at macros, which allow you to repeat preset series of commands in order to save time.
For both text objects and macros, we will walk you through some examples of how they are used in order to give you a practical understanding of them.
This course is ideal for anyone who needs to edit text files in a command-line environment.
If you want to follow along with the exercises in this course, you should have the Vim text editor installed on your computer.
If you want to follow along with the exercise(s) in this course, you can find the necessary resources here.
You've already learned a couple of different ways to repeat single commands. For example, you can proceed a command with a count to have that command repeat multiple times. 3dW, for instance, will repeat dW three times, and ultimately end up deleting three words. If you wanted to repeat that command again, you could simply type a period, which is the dot command, and three more words will be deleted. But what if you need to repeat a series of commands? How do you do that? Well, you use macros. Actually, Vim calls macros complex repeats, because they go beyond simple one-command repetitions and can involve many steps. One of the most common uses of Vim macros is to change the format of data or text. You can do things like normalize data into a desired format, move columns around in a CSV file, delete extraneous texts within a line to clean up your data, and so much more. In short, you should consider using a macro any time you have a complex or lengthy edit that needs to be repeated multiple times. Let me show you how easy it is to create macros in Vim. First, I'm going to open up a terminal on my system and navigate to where I extracted the contents of the course download archive. And for me, that's my Downloads folder. And then go into the vimclass folder, and now I'm going to open the macros.txt file. As always, you can follow along with me now or wait for the practice exercise that follows. Vim macros are nothing more than a recorded sequence of keystrokes. These keystrokes are actually saved in registers. When you play back a macro, all the keystrokes recorded in the register are played back, and it's exactly the same as if you were to type those keystrokes again. This means you have access to the full power of Vim and your macros. The only slight limitation is that you can't make an existing macro record a new macro. But past that, you can do pretty much anything you can think of. To start recording a macro, use the q command followed by a register. Let's say you wanna record a macro into the a register. To do that, type qa. Now you'll notice recording @a is displayed on a status line at the bottom of the screen, letting you know that you're currently recording a macro. Let's create a very simple macro. Let's insert the text note followed by a colon and a space at the beginning of the line. And to do that, we could use capital I to insert text at the beginning of the line, and now we just type our text, NOTE: space, and hit Esc. When you're done recording your macro, type q. Now the recording message at the bottom of your screen disappears, and your keystrokes are saved in your specified register. In this example, that was the a register. So let's look at that register with :reg a and and hit Enter. You see all the characters you typed. The capital I, which puts you in insert mode at the beginning of the line, the text of NOTE: space, and the Esc key is represented by the caret and open bracket. By the way, you can actually use that key combination in place of Esc to get back to normal mode, that key combination being Ctrl or open bracket. So if for some reason the Esc isn't working, you can just use that keystroke. Anyway, when you see that NOTE, it's the same thing as hitting the Esc key. So now you have a macro recorded and saved into the a register. To play it back, use the @ sign followed by the register. Let's move down to the next line with j and type @a. All the keystrokes are replayed that were previously recorded into the a register resulting in NOTE: space being prepended to the current line. A very quick way to repeat the most recently executed macro is to use @ sign @ sign. So let's move down to the next line. And I'm gonna type Shift + 2 twice, which is @@ on my keyboard, and that macro is repeated. You might've noticed that every time you wanted to execute this macro, you had to first position the cursor on the line and then execute the macro. Because macro simply replay keystrokes, we can include a j keystroke to position the cursor on the next line for us. That way, when we replay the macro, it changes the current line and puts you in position on the next line. With this idea in mind, let's talk about some best practices when it comes to recording macros. One of the things I like to do is make sure the cursor starts at the same position every single time. One of the simplest ways to do this is to start your macro with zero, which moves the cursor to the very beginning of the line. After you've normalized your cursor position, you can then make your edits and execute your desired commands. When you're done, move the cursor to the next line with j and finally stop recording with q. Now I'm going to position my cursor on the line that reads, "Think big," and I'll just do that with a /Thi, there we go, I'll press Enter. And now I'm just gonna move our view up the screen by typing z and Enter so we can get a better view of what's going on. Now let's record another macro. This time let's save it into the b register. So let's type qb. Now you're going to make sure your cursor goes to the very beginning of the line by typing zero. Let's say you want to insert the word tip at the beginning of each line. And since your cursor is at position zero, you can just type a lowercase i to enter insert mode followed by TIP: and a space, and now we'll hit Esc to get back to normal mode. If that's all you want to change on the line, then just type j to move down to the next line, and finally we can stop the recording with q. Let's replay our macro with @b. You'll notice that the line changed and now the cursor is in position on the next line. If you typed @@, you would execute the same macro again which makes the same edit and moves the cursor down to the next line. We'll just hit @@ again, and finally @@ again to complete all the edits for this entire block. Let's undo our changes there with a series of Us. So, u, u, u, u and u. And now we're back to how that block looked like originally. Now let's say you want to repeat that macro over the entire block of text all at once. You can see that there are five lines here in this block of text. So like any other command, you can repeat a macro by using account. So when you type 5@b, the entire block of text is transformed. Now let's move to this next block of text and position that higher in our view is z and Enter. Now let's say we want to create a slightly more involved macro. Let's say we want to remove first name and last name from each of these lines. Let's create a new macro using the c register. So we can type qc, and we'll normalize our cursor position by typing zero. There are many ways to go about this, of course, but I'm going to delete the first two words and I'm going to use 2d capital W, because capital W ignores punctuation. So there you can see, FIRST NAME: space was deleted with our command there. Now let's advance to the word LAST. I'm going to use f followed by capital L, a forward search on the same line to the next occurrence of capital L. Because we need to do the exact same thing as the last command, we can use the dot command. We'll do that again, dot, and we have deleted those two words. Now we can stop the recording with q. Let's look at the contents of the register with :reg c and pressing Enter. If you wanted to repeat this macro on multiple lines, it would be nice to position the cursor on the next line. But as you can see, I didn't do that. The good news is that macros use registers, and as you know, registers can be upended to. So to append a j to the macro, we can use qC. Just as you learned when you were working with registers, using the capitalized register letter appends to the register. So now I just need to type a j and hit q to finish our update. Now let's look at the register again, :reg c. Now you can see that the j was appended to the end of that register. Now let's test our macro with @c. That looks good, so I'll just repeat it a few more times to finish formatting these lines. So I'll just type @@, @@, and @@ again. Up until this point you've just been inserting and deleting text on a line, but remember that macro simply replay keystrokes so you can use commands in different modes too. Let's move to the next bit of text, so I'll hit j and then z and Enter. Let's say you wanna change these lines in a few different ways. For starters, you wanna replace the double quotes with single quotes. Next you wanna get rid of the parentheses on the line. Also, you wanna remove the equal sign followed by the greater sign. By the way, some people call that punctuation combination a fat comma, a hash rocket, or a fat arrow. Anyway, let's say you also wanna make sure that the three strings are separated by a comma, and finally you wanna make sure usa is capitalized. Those are a lot of changes. Let's tackle them one by one. Just move down to the first line of text here, and let's record this macro into the d register. So, let's type q and d. Now let's make sure we normalize our cursor position by typing zero to put us at the beginning of the line no matter where we start at on the line. Now, an easy way to replace the double quotes with single quotes is to use the substitute command. So we can type :colon s/"/'/g and press Enter. You can also get rid of the parenthesis by using the substitute command as well. So we can actually do this, :s/ open parenthesis //, press Enter, and let's do it again for the backslash. So we'll do :s/ close parenthesis // and hit Enter. To get rid of the fat arrow, you can use the substitute command yet again. Actually, we can do two things at once here. We can get rid of that punctuation and replace it with a comma. So here we could use :s/ =>/ and we're gonna replace that with ,/ to close our substitution, and we'll press Enter. The last change you need to make is the capitalization of usa. Again, we can use the substitute command here. So we can do :s/usa/USA in all uppercase characters / and press Enter. Those are all the edits we wanna make. So we can position our cursor on the next line and stop recording with q. So I'll hit j and press q. Let's look at the macro we just created with :reg d. Each time you see caret M or Ctrl + M, that's where you press the Enter key. By the way, positioning the cursor at the very beginning of the line with zero really wasn't needed in this case. It's still a good practice, especially if you don't know exactly how you're going to perform all the edits in the macro. Of course, you could always normalize the cursor position later in the macro if needed. Anyway, I just wanted to point this out, and as always, do what makes sense to you. Up until this point, you've been eyeballing how many times you need to repeat a macro and then supplying that count. That works when you're working with small data sets. But if you want to apply a macro to many lines, maybe lines that even scroll beyond the end of your screen, you'll need a way to apply your macro to that exact range. And if you need to apply the macro to every line in the file, you could use Ctrl + G to get the line count and then use that line count with the macro. Let me hit Enter here, and let's do Ctrl + G. Now we could use line counter, this file which says 50 lines, and then we could do something like 50@c. But there's an even better way even when you know the line count. And that way is with the normal command. First you enter command mode, supply a range, type the normal command and then follow it with the macro. First, let's turn on line numbering with :set nu and pressing Enter. Now you can see that you want to apply this macro on lines 27 through 35. Now enter command mode with :, and let supply the range, which is 27,35, type the command normal, and finally supply a macro which is @d in this case, and press Enter. Now that macro is executed over the specified range. In an example where you wanted to change every line in a file, you could use a range like .,$ which represents the current line through the end of the file. Note that macros don't have to operate just on a single line. Let's run through a quick example that demonstrates this point. Let's say you have a list of websites with their names on one line and their IP address on the line that follows, and each one of these pairs is separated by a blank line. Let's say you want to format this line so that the IP address is first on the line, followed by the website name, and then nothing else on the line. I'm gonna position my cursor here at the beginning of this list of host names and addresses. Type z and Enter to move the view up our screen here. And then I'm going to start recording our macro by typing qe. Make sure your cursor starts in the same position each time by using zero. Now, move down to the next line with j and then delete the IP address with D. Now move back up to the original line and paste it with kP. You want a space after the IP address, so just use a space, and hit Esc to get back to normal mode. You want to delete it everything after the host name. So you can just use a forward search with / h and press Enter. Now delete the rest of the line with D, Shift + D. Now you wanna delete the blank line, so you can use j2dd. Now the cursor is in position so you can end the recording with q. We have two more sets of data, so we can just use use 2@e and you're done. Another scenario you may find yourself in with macros is that you wanna change something in the macro. You already know how you can append to a macro but what if you wanna do something like insert zero at the beginning of your macro? The good news is you're just working with registers so you can paste the contents of your register, modify it, and yank it back into the register. Let's do that with the contents of register a. Let's move to a blank line here and paste the contents with "ap. Let's say you wanna start the line with A space as an ANOTE instead of just the word NOTE. So we'll position our cursor back it in, I can just use a reverse search N, and insert an A with I, A space, and hit Esc to get back to normal mode. Now all you need save your changes into the register. So position your cursor at the beginning of the line with zero, now yank in the text with "ay$. That yanks all the way to the end of the line. Now you can trial your updated macro on the next line to see if it works. So I'll just hit j to go to the next line and then type @a. And you see that your change was indeed saved. Let's say you wanna save one of your macros for future use. There are a couple of ways to go about this. One is relying on the viminfo file which is stored in your home directory as .viminfo for Unix-like systems such as Linux and Mac, and _viminfo on Windows systems. The viminfo file stores a lot of information like the command line history, the search history, and the contents of non-empty registers. When Vim starts, it reads the contents of the viminfo file. So if you were to exit out of Vim and then start it tomorrow, all the registers would be available to you so you could just use your macro right away. The only problem with this method is that, if you overwrite the register, then you lose the contents of your macro. You could get around this by assigning your must-have macros to registers and just make sure that you never use them for anything else. However, there's a more reliable way to save your macros and that's in your vimrc file. The vimrc file is covered in more detail elsewhere in this course, but briefly it's a file that contains initialization commands. On Unix-like systems, it's stored in your home directory as .vimrc, and on Windows systems, it's stored in your home directory as _vimrc. When you're editing your vimrc file, use the following syntax. Now, I'm just going to place this in this example file, but when you're doing this for real, you're going to put it in your vmrc file. Again, see the vmrc lesson for more details. So what we wanna do is create a line that starts with the word let, followed by a space, followed by the @ sign, and then the registered letter you want to store your macro into. Let's use d for example. Now we can follow that with an equal sign and a single quote. The easiest way to save the contents of your prerecorded macro is to simply paste it. So you can paste the contents of the d register with "dp. Now all that's left to do is to append a single quote and we can do that by hitting a' and pressing Esc. This is pretty much a variable assignment statement. You're pretty much programming your text editor at this point. Anyway, when you start Vim, the contents of the d register will be exactly as specified in the vimrc file. If you were to overwrite the contents of the d register, that would last for the duration of that Vim session. But when you start Vim again, that let command will set the contents of the d register. I highly recommend the method of pasting your pre-recorded macros in order to save them. That way you know they work and they contain all the special characters you need. However, you can manually enter macros too. For example, let's create a macro for the t register that inserts TODO at the beginning of the current line and then positions the cursor on them line below it. To do that, I'll just start a new line here and type let @t, and then we'll set this equal to insert mode, capital I, TODO: and a space. To return to normal mode, you want to include the Esc character in your macro. But if you were just to hit Esc now, you would just exit out of this insert mode. If you just type that caret symbol followed by the opening bracket like this, thinking you would cause Vim to interpret that as an Esc character, it would be a good guess but it would be wrong. And I'll backspace over that and tell you how to insert a literal character. And to do that, you just type Ctrl + V and then type the character. So now we'll just hit Esc, and now the proper character has been inserted. Finally, we can end this macro with j and add the closing single quotation mark. If you have single quotes that are in your macro, you can surround the let statement with double quotes. So that's how you create, edit, play, and save macros. Let's do a quick recap before we wrap this lesson up. First off, you learned that Vim macros are nothing more than a series of keystrokes. You used registers to store those keystrokes. To record a macro, you used the q command followed by the register you want to record into. If you want to append to the macro, then just use q CAPITAL_REGISTER name. You also learned how to play back those keystrokes with the @ symbol followed by the register. You quickly repeated the last macro with @@. You also picked up a couple of tips about creating macros such as normalizing your cursor position at the beginning of the macro and positioning your cursor on the next line at the end of the macro so you can easily repeat it. You also learned how to control the area where a macro will operate by entering command mode then supplying a range, following it with the normal command, and finally providing the macro with @ REGISTER. You also learned how to repeat a macro multiple times by proceeding it with a count. Finally you learned how to save your macros in your vimrc file so they're available whenever you need them.
Jason is the founder of the Linux Training Academy as well as the author of "Linux for Beginners" and "Command Line Kung Fu." He has over 20 years of professional Linux experience, having worked for industry leaders such as Hewlett-Packard, Xerox, UPS, FireEye, and Amazon.com. Nothing gives him more satisfaction than knowing he has helped thousands of IT professionals level up their careers through his many books and courses.