Vim Buffers & Windows
The course is part of this learning path
This course covers how to open up multiple files or multiple buffers, and navigate between them. You'll also learn how to execute commands over every buffer with a ":bufdo" command as well as how to work with hidden buffers. You get a chance to follow along with an exercise in which you practice working with multiple buffers.
Then we look at windows in Vim which allow you to view more than one of those buffers at the same time or view the same buffer in multiple places, all at once.
This course is ideal for anyone who needs to edit text files in a command-line environment using Vim.
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 might find yourself in a situation where you want to edit or at least view multiple files at once and quickly switch between them. For example, if you're programming in C, you might wanna quickly switch between your source code file and your header file. Maybe you're writing tests for your code so you're switching back and forth between your source code and your test file. Maybe you're a system administrator and you need to make changes to a main configuration file, as well as some or all of the files that that main configuration file includes. Maybe you just want a temporary place to keep some notes while you're working on a file. One way to do things like this would be to have multiple terminals open. You could even use something called a terminal multiplexer like screen or Tmux or you can use VIM's built in mechanisms for handling multiple files which is what we're going to be covering in this lesson. Let's start out by talking about buffers. Whether you realize it or not, you've been using buffers this whole time. Anytime you open a file with VIM, it reads the contents of that file into memory. That end memory representation of the file is what VIM calls a buffer. A common computer science definition of a buffer is a temporary memory area in which data is stored while it is being processed or transferred. Said another way, a buffer is a file loaded into memory for editing. The original file remains unchanged until you write that buffer to the file. When you think about it, it makes total sense. When you make a change, it's not automatically saved to the file. Only the buffer is updated. When you're sure about your changes then you write those changes to the associated underlying file. If you don't like those changes then you can discard the buffer and the actual file remains unchanged. By the way, even though a buffer is typically associated with a file, it doesn't have to be. For example, when you start VIM without supplying a file for it to open, VIM starts with an empty buffer. If you want to save the changes to that buffer, then you have to tell VIM what file to write those changes to. So again, a buffer resides in memory. Let's get into some examples by opening several files at once. But first let me change to where I extracted the contents of the course download archive. One way to open several files at once is to supply multiple files as arguments to the VIM command. For example, I could type "vim buf-ant.txt buf-bed.txt" and hit enter. What you see here is the contents of the first file supplied on the command line even though we actually opened two files. If you wanna open even more files, you can do so within VIM by using the edit command. Let's open another file with ":e" which is the shorthand version of edit, "buf-cat.txt" and press enter. Now the file is opened and we can see its contents. We still have two other files open even though we can't see them. We can even add another file with this. Let's add "e buf-dad.txt" and press enter. Now we have a total four files open. We'll get back to dealing with multiple files in just a second, but first let me quit them with ":q!" Another way to open multiple files at once is to use your shells expansion feature. A common shell expansion is the asterisk which matches zero or more characters. So you can open every file that starts with the characters "buf" by typing "vim buf*" and then pressing enter. What happens when you execute that command is your command line shell expands the asterisk into the matching files which then become arguments to the VIM command. This has nothing to do with VIM. This is how your shell works with any command. I'm not gonna get into every possible shell expansion for every possible operating system, but just know that this is a common way to open multiple files at once. So now we have all the files that start with "buf" open in VIM even though we can only see one file, which is "buf-ant.txt." To view all the open buffers, let's use the buffers command. So we'll type ":buffers" and press enter. This displays the list of buffers. In the far left column, you see a number. This number is a unique number for each buffer. By the way, this number will not change for the duration of your current VIM session. So the "buf-ant.txt" file will always be buffer number one. The next column is used for indicators and flags. The indicators and flags for buffer one are a percent sign and an "a." The next column displays the file name and the last column displays your current cursor position in that buffer. Let's quickly look at the help for the buffers command with ":h :buffers" and pressing enter. You'll see that you can also run ":files" or ":ls" to execute the exact same command as ":buffer." Personally, I like the ":ls" command because it's short for list and it's one of the first commands you learn on a Unix or Linux system. Let's exit out of help here with ":q" and press enter. So now you know how to see the buffers you have opened with a buffers command, or as I like to use the "ls" command. So let me demonstrate that here, ":ls" and pressing enter. So how do we open another buffer? Well, you use the buffer command and either supply a buffer number or a buffer name, which is the same as the file name. So to bring the "buf-bed.txt" file into our window, we can type ":buffer" space "2" and press enter. By the way, the shorthand version of the buffer command is ":b" so let's use that to open up the file name "buf-cat.txt" which is identified by buffer number three. So I'll type ":b3" and press enter. Let's use that command to view buffer four which is associated with the file name "buf-dad.txt" and to do that we can use ":b buf-dad.txt." Here, we're supplying the buffer name or the file name and press enter. So again, you can supply the buffer number or buffer name as an argument to the buffer command to place that buffer in the current window. You can also use tab completion. So let's type ":b" space and hit the tab key. Now you can cycle through your open buffers and simply hit enter when you're at the one you want to open. So I'll just hit tab a couple of times here to go to this file and press enter and now that buffer is open. You can also do this. You can hit ":b" space control "D" and that gives you a list of buffers to select from. Then you can type out the buffer name or use tab completion to open the desired buffer. I'm gonna hit escape because I'm just gonna stay in this buffer. You can move to the next buffer with the "bnext" command. So ":bnext" press enter. The shorter version of the "bnext" command is "bn" so we can type ":bn." This actually loops through your buffer list. So as you saw here, we were at the last buffer, buffer four in our list and when we executed the "bn" command, we actually looped back around to the first buffer or the beginning of our buffer list. And so let's keep doing this, "bn," "bn," "bn." Now we're at the last buffer, "bn," and we're back at the first buffer. You can also move in the other direction with "bprevious," ":bprevious" and press enter. Luckily, there is a shorter version of that command which is ":bp." This command will also wrap around the buffer list. So if you're at the first buffer and you execute ":bp" you'll end up looking at the last buffer in your buffer list. and we already kind of saw this, "bp," "bp." This is our first buffer, we're at buffer one, type "bp" and now we're back to buffer four when we wrapped around the buffer list. There's also a "bfirst" command which takes you to the first buffer. The short version of that is "bf" so let's type ":bf" and now we're at buffer one. Also, there's a "blast" command which takes you to the last buffer. And the shorthand version of that command is ":bl" press enter, and now we're at the last a buffer in our list. Let's open up buffer number two with a buffer command that we just learned a second ago. So we'll do ":b2" and press enter. If you want to quickly switch back to the previously opened buffer, use control caret symbol which is control shift six on my keyboard. Wanna get back to the other buffer? Well, use control shift six again. I can keep hitting control caret and quickly switch back and forth between those buffers. Now, if we look at our buffers list with ":ls" and press enter, you'll see "%a" in the indicator column next to the current buffer loaded in the window. The percent sign means it's the buffer in the current window. and the "a" means it's an active buffer which means it's loaded and visible. You'll notice a buffer that has a pound sign in the indicator column next to it. The pound sign represents the alternate buffer which is the buffer that you were previously editing. So when you type control caret symbol, it switches to the alternate buffer. Let's do that now, control shift six. Now, when we look at the buffers with ":ls" and press enter, you'll see that the other buffer we were just looking at is now the alternate buffer. You can actually this notation with the buffer command. So another way to quickly switch back to the alternate buffer is ":b#." Let's move back to the first buffer with ":b1." Now let's make a small change to this file. We'll just insert some text here. I'll just hit I to go into insert mode, type "ant" and press escape. Now let's look at the buffers with ":ls" and press enter. You'll see a plus sign indicator for the buffer that you're working on. This signifies that the buffer has been modified, but those changes have not been saved. By default, if we try to switch to another buffer without saving our changes, we'll get an error. So let me do that here with ":bn" to switch to the next buffer and press enter. It tells us that our modifications haven't been saved with the no write since last change message. There are a couple of ways to handle this. One way is to write our changes to the file and then load the other buffer. So what I can do here is just type ":w" to write our changes. Now we can load the other buffer with ":bn" and press enter. Let's make a change to this buffer. I'll go into insert mode and type "bed" and hit escape. Now let's try to switch again, ":bn." This time let's take the error messages guidance and append an exclamation mark to the command to force it. So what we can do is ":bn!" and press enter. Now let's look at our buffers. The buffer we just changed has a plus sign because it has unsaved changes and now it also has an age indicator which means it's what VIM calls a hidden buffer. A buffer can be in one of three states. Active, meaning it's loaded into memory and displayed in a window, hidden, which means it's loaded into memory and not displayed in a window, and finally it can be inactive, meaning in is not loaded into memory and it is not being displayed. So the buffers that don't have any indicators are actually not loaded into memory. When you switch to them, they are then loaded into memory. So when you switch away from them VIM unloads them and freeze that memory. Even though the file itself isn't loaded into memory when it's inactive, VIM remembers the metadata about that file in buffer. For example, it remembers what line you are on, the setting specific to that buffer, and so on. If you wanna change this default behavior of unloading a buffer each time you switch away from it, you can turn on the hidden option with ":set hidden" and press enter. This allows you to edit multiple files at once without saving before switching buffers or forcing the switch with an exclamation mark. Once a buffer is loaded into memory, it stays in memory. Said another way, when you load a different buffer in the window, the buffer you were just editing becomes hidden. Now let's make a change to this file. I'll insert the word "cat" here and press escape. Now let's move to the next buffer, ":bn" and press enter. We didn't receive a message about writing our changes even though we didn't save our changes. Let's look at the buffers here, ":ls" and I'll hit enter. Now when we look at the buffers, we can see that the buffer we just changed is now hidden. Let's keep moving through the buffers here. I'll hit ":bn" in and press enter, ":bn" and now let's look at the buffers and they're all either active or hidden. Even if you don't make a change to a buffer, it becomes hidden because we turned on the hidden option. If you forget to save your changes to one or more of your buffers and try to exit, VIM will give you an error message and switch to the first buffer with unsaved changes so you can either save or abandon them. This even works with ":q!" Let's make a change here. And let's move away to another buffer, so now that one is definitely hidden with a change. And now what we can do is try to exit with ":q!" You can see that we get an error message and when we hit enter here, that modified buffer is brought into the foreground. If you want to save your change then you can use ":w" and press enter. Or if you want to discard your changes then you can just execute ":q!" again. So I'm actually going to write this to the file. I'll just type "w" and press enter. So using the hidden option is fairly safe. If you like this option, you can add it to your VIM RC file. The VIM RC file is of course covered in depth in another lesson. By the way, if you want to abandon all of your changes and all of your buffers, then you can use the ":qall!" command. Likewise, if you wanna save all the changes to all of your buffers, you can use the ":wall" command. You already know how to open a file for editing in the current window with a ":e" command. If you want to open a file without switching to it immediately, you can use the ":badd" command. Let's do that here. I'll do ":badd modes.txt" and press enter. Notice how we're still looking at our current buffer but let's look at our buffer lists with ":ls." So it's available to you when you want to use it. Now let's switch to it with ":b6" and press enter. Let's say you're done with a buffer and you want to remove it from your list of buffers. To do that, use the "bdelete" command or ":bd" for short. "Bdelete" unloads, the current buffer from memory and flags it as unlisted. When you look at the buffer list with ":ls" you won't see it in the list. You can specify a buffer to delete by passing its name or number as an argument to ":bd." So let's delete buffer three with ":bd3" and press enter. Now let's look at our list. It's gone. Now we can add it back by using ":badd buf-cat.txt" and press enter. Now when we look at it here, it's back in our buffer list. You can also give the ":bd" command arrange so you can do something like this, ":1,3bd" and press enter. Now we can look at our buffers with ":ls." You can see we only have one buffer left. By the way, if you want to delete all the buffers, you can use the special range of percent sign. So we could do this, ":%bd" and press enter. Now all the buffers have been deleted and VIM gives you a fresh, no named buffer to work with, just like you would have if you started VIM without opening a file. Let's reopen our buffers quickly. I'll just quickly exit out of them and reload them here, ":q" press enter, execute "vim buf*" and press enter again. If you want to execute a command in every buffer, use the ":bufdo" command. For example, let's turn on line numbering for each buffer with ":bufdo set nu: and let's press enter. Now when we cycle through the buffers, we'll see that they all have line numbering enabled. So I'll do this, ":bn," ":bn," ":bn," ":bn," et cetera, and sure enough, they all have line numbers enabled. Let's perform a global substitution across all of our buffers. Let's see if this will work. We'll use ":bufdo" global substitution, "S," let's substitute the pound sign here with an at symbol and we'll use the "G" flag so that it replaces everything on each line and let's hit enter and see what happens. We get an error message saying that we haven't saved our changes. What happened was ":bufdo" executed the command in the current window and got an error when it tried to switch to the next buffer so it stopped. There are a couple of ways to deal with this. First, let me undo this change. I'll hit enter here and then hit "u" to undo. One way we can handle this is to save our changes along the way. So let me just use my history here, the same command and type pipe symbol "nw." The pipe symbol in VIM is the command separator. So what this command will do is execute the substitute command first, then execute the write command. The next buffer will be loaded and the substitute command will get executed and then the write command will get executed on that buffer and so on and so forth. So let's try it here. It looks like it worked. Let's check out a different buffer and see if it did. So I'll hit enter and ":bn," ":bn," ":bn." Sure enough, all those pound signs look like they were changed to at symbols. The other way to handle this is to use the hidden option which we talked about earlier. Right now, hidden is off because I restarted VIM and it's not in my VIM RC file. We can check the current status of that setting with this, ":set hidden?" press enter and sure enough it says no hidden. Let's make our command fail again here. Let's do ":bufdo" global substitution. Let's replace the at symbol with an asterisk, "G" here and press enter. And sure enough, it fails. Let me undo that with "u." Now, let's turn on the hidden option. So we'll do ":set hidden" press enter, ":set hidden?" Sure enough, hidden option is on. So now let's try our command again. I'll just hit ":b," press the up arrow to use my history here very quickly. So that's the last ":bufdo" command we ran. Let me hit enter and see what happens. Great, we see our substitutions have been made. Now let's look at our buffers here with ":ls." You can see plus signs for each buffer because they've all been modified, but not saved. If we want to save our changes we can use this command, ":wall" which stands for write all. Now let's look at our buffers with ":ls" and the plus symbol is gone because all of our changes have been saved. Before we wrap things up, I wanna show you just one more command and that command is ":explore" or ":E" for short. When you execute this command, you get a file explorer window. You can use your normal VIM navigation commands like "J," "K," control "F," forward search, and so on. Once you've found the file you want to open, then place your cursor somewhere underneath that file and press enter. So let me open the VIM RC sample file here and press enter. If you decide not to open any files, then you can use the ":bd" command because this is just a special buffer that VIM is using for this. So we'll do it again. ":E" here, let's say we decide not to open any files, ":bd" to delete this current buffer and we're looking back at our first buffer. Let's quickly recap this lesson. First, you learned how to open up multiple files or multiple buffers with the ":e" or edit command. You also used shell expansion to open multiple files as well. You learned how to list your buffers with the ":ls" or ":buffers" command. Additionally, you learned how to switch to a different buffer with the ":buffer" command. You can either supply it a number or a name. You also learned how to move to the next buffer with ":bn" and the previous buffer with ":bp." Next, we talked briefly about how to move to the last buffer with ":bl" and the first buffer with ":bf." Using the ":e" or edit command loads of buffer into the current window. If you want to load a buffer and not switch to it immediately, you learn how to use the ":badd" command. Additionally, when you're done with the buffer you learned how to delete it with the ":bd" or ":bdelete" command. Next, you learned how to execute commands over every buffer with a ":bufdo" command. Finally, you learned about hidden buffers and how to work with them easier by using the set hidden option.
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.