Mac OS X Command Line 101
by Richard Burton
More Command Line Text Editing
Part XIII of this series...
August 16th, 2002
"I've seen three!"
- David Hatch and Bill Oddie, I'm Sorry I'll Read That Again, "Macbeth""
This series is designed to help you learn more about the Mac OS X command line. If you have any questions about what you read here, check out the earlier columns, write back in the comments below, or join us in the Hardcore X! forum.
The previous column took a look at how to do simple, basic things in the vi editor. This was enough to be getting on with, as the saying goes, but there is much more available to you. As promised, we'll take a fuller look at the commands available to you in this installment. For now, type:
This will re-open the file we used last week (assuming you saved it) in vi so you can try out the various commands in today's column. I won't be telling you exactly what to do and where, because you are probably old enough to experiment (or mess around) on your own.
If you happen to find a list of the vi commands in alphabetical order, you will notice that many of the commands invoked by the uppercase and lowercase of the same letter seem to be associated. For example, we have seen that "r" will replace one character of text, while "R" will place you in insert mode, replacing text until you hit ESCAPE. Where "x" deleted the character under the cursor, "X" deletes the character before the cursor.
Often, the uppercase command does something similar on/to/about an entire line. For example, an "i" will put you into insert mode, while an "I" will put you in insert mode at the beginning of the current line. An "a" will also put you in insert mode, appending text after the cursor, while an "A" will append text, not where the cursor is now, but at the end of the current line. And where a "u" 'undoes' your previous command, a "U" restores the current line to its previous state.
The "C" and "D" commands are also similar to their lowercase counterparts. Recall that "c" is the change operator; you can use it to change a word, a line, etc. "C" will change text from the cursor to the end of the line. (As always, hit ESCAPE to stop changing.) Likewise, where "d" is the delete operator, "D" will delete all characters from the cursor to the end of the line.
"W", "B", and "E" are the same as their lowercase counterparts, but instead of moving a line at a time (recall that "h", "j", "k", and "l" do this), they ignore punctuation when moving forward/backward one word. For example, "w", "b", and "e" would see the word "We're" as three words: "We", "'" (the single quote as a word), and "re". "W", "B", and "E" see it as one. It may seem like these three commands have limited usefulness, and I wouldn't disagree. However, they can be useful for mapping; more on that later.
Two other sets of commands are more useful in mapping than in day-to-day editing. "f" and "F" will search forward and backward, respectively, the current line for a character. Thus, if you type fx in command mode, either the cursor will move forward to the next 'x' on the current line, or the system will beep for an error if there is no 'x' after the cursor. "t" and "T" are nigh on the same thing, but not quite. They will search forward ("t") or backward ("T") in the current line for the character before the character you provide. Thus, typing tx in command mode will move the cursor forward to the character before the next 'x' on the current line, or the system will beep. Again, these are mostly used for mapping.
"o" and "O" are another pair. "o" will open up a new line for editting after the current line. "O" does the same, but before the current line.
However, not every pair of lowercase/uppercase letters correspond to similar commands. For one thing, commands are not defined for every letter. For example, "q" is undefined, while "Q" will place you into the ex editor. (If you want to get back to vi, just type "vi" at the colon.) Similarly, "g" is undefined, but "G" moves the cursor to the last line in the file. (This is the same as invoking the ex command :$ .) "G" will, oddly enough, take a count, but it doesn't move you to the last line repeatedly. (That would be silly.) Typing nG in command mode will take you to line ... well, whatever number you use for n. (This is the same as invoking the ex command :n where n is, of course, the line number.) If you don't know what your current line number is, just type a CONTROL-G (or, if you prefer, a :.= to run the ex version of the command.)
The corresponding uppercase letters of the movement commands (hjkl) do not mimic their lowercase counterparts. "H" moves you to the top line of the screen, not the beginning of the line. (Recall that "0", zero, does that.) "J" will join the following line to the current line. This can be quite useful if you are doing a copy-and-paste of text that takes up more than one line. "K" is undefined. "L" takes a count and moves you to that number of lines before the last line on the screen. With no count, it moves the cursor to the last line. (A side note here is that "L" uses lines on the screen, not lines as determined by when you hit RETURN.)
Now, three basic functions of an editor are to cut, copy, and paste text. We have seen how to cut text with "d" and "D". We can, of course, copy text by highlighting it and selecting it from the dropdown menu at the top of the computer screen. Likewise, by typing "i" to go into insert mode, we can use the dropdown menu to paste text. While that is useful, it is not the Unix way. Also, vi was written before GUIs were around. (At least I think it was.) Therefore, you would expect vi to have the ability to copy and paste text, and you would be right, you clever person.
When you delete text, it is copied into a buffer so that it can be pasted later. If you just want to copy, not cut, vi lets you do that, too. The "y" operator will copy (yank) text into a buffer (without deleting it) so it can be pasted. yw will copy a word; yy will copy a line. Both take a count. Also, you can use different buffers. vi stores the text from the last nine deletes in separate buffers (numbered 1-9). Typing "ayy (a quote followed by a letter followed by two y's) will copy the text from the current line into a buffer labeled a. This allows you to copy to, and to paste from, several buffers at the same time, rather than the standard one buffer that the desktop uses.
The "p" and "P" commands let you paste/put text. When you have text in a buffer, "p" pastes the text after the cursor; "P" pastes it before the cursor. Now, given that you can yank text into different buffers that you label, it's no surprise that you can also paste from those buffers. "p" takes a count, sort of; typing "np (double quote followed by a number up to nine followed by a 'p') will paste the text in delete buffer number 'n' after the cursor. Typing "aP (double quote followed by the buffer's letter label followed by the letter 'P') will paste the text from that buffer before the cursor. Congratulations, you now have a cut-and-paste utility that is more powerful than GUI editors'.
There is one more form of pasting. If you want to read text from another file and include it wholesale into the file you are editing, there is an ex command that lets you do this. By typing :r filename, the contents of the file filename get copied into the file after the cursor. Again, this can be a big time saver.
Okay, back to mapping. (And you thought I'd forgotten.) There are several letters that do not have commands associated with them: "g", "K", "v", "V", and several CONTROL- characters. These can be used to create aliases so that one keystroke can replace several. For example, I often type "teh" for "the" in spite of all my practice. It happens all teh --, er the time. To correct it, I always move the cursor to the 'e', type an x to delete the 'e' (which places the cursor over the 'h'), then type a 'p' to paste the 'e' after the 'h'. Since I do this a lot, I'd like to be able to replace those two keystrokes with one. vi lets me do this every time I start it. And the best part is, I can use vi to set it up. Can I get a w00tness?
At the command line, cd to your home directory and look for the file .exrc:
[localhost:~] dr_unix% ls -a .exrc
ls: .exrc: No such file or directory
In my case, it isn't there, so I don't have to worry about copying it (cp) before changing it. (This is always a good idea if you don't know what you are doing. I rarely do.) So, after a cp .exrc .exrc_bak if that applies to you, type the following at the command line:
[localhost:~] dr_unix% vi .exrc
which gives the usual
.exrc: new file: line 1
Now what I want to do is set the command "v" to switch the letter under the cursor with the one after it. This is done by issuing the command "x" followed by the command "p". So, in the .exrc file, I add the following line:
map v xp
After ESCAPE-ing to exit input mode, I type the "ZZ" command to save the file and quit vi. Now I can test if this works. At the command line I type:
[localhost:~] dr_unix% vi maptest
and I add the line:
Hitting ESCAPE to go back to command mode, I move the cursor over the 'e' in 'teh'. I then enter the "v" command, wave a wand, and as if by Unix, the line becomes:
his is the end.
While changing a two-keystroke command for a one-keystroke command isn't that great an improvement, these maps can, of course, be as complex as you want. (The usefulness of overly complex maps is for you to decide.) For example, if you have a tendency to switch two words as you type, you can add the following to your .exrc file:
map V dwElp
This creates a new command, "V", which will delete a word ("dw"), move to the end of the word that is now under the cursor (using "E" instead of "e" in case the word contains an apostrophe), moves one character to the right ("l"), then pastes the word that was just deleted ("p"). Voila, you are now a vi power user, a Unix genius, and all-around geek-about town.
Of course, I saved the best until last. The "/" and "?" commands are another associated pair. Strictly speaking, "?" is not the uppercase version of the "/" character, but they are on the same key, and that's close enough for jazz. The "/" and "?" commands let you search forward and backward, respectively, from the cursor for the regular expression you provide after the command. They --
What's that? We haven't covered regular expressions yet? [Looks at watch.] Oh, dash it, that will have to wait until the next column.
You are encouraged to send Richard your comments, or to post them below.
Most Recent Mac OS X Command Line 101 Columns
Command Line History & Editing Your Commands
Pico: An Easy To Use Command Line Editor
Understanding The "grep" Command In Mac OS X
Command Line History & Editing Your Commands
Mac OS X Command Line 101 Archives
Back to The Mac Observer For More Mac News!
Richard Burton is a longtime Unix programmer and a handsome brute. He spends his spare time yelling at the television during Colts and Pacers games, writing politically incorrect short stories, and trying to shoot the neighbor's cat (not really) nesting in his garage. He can be seen running roughshod over the TMO forums under the alias tbone1.