The h, j, k, and l commands reflect the arrow keys on those old VT100 terminals, and always
work. Sometimes the arrow keys also do the same things, depending on your keyboard.
Note that symbols such as $, which mean the end of the line (or file in : mode, see below),
and ^ (beginning of line) are not just for moving in the file, but also
retain their meanings when you define segments of the text to do substitutes (see below).
The editor is a lot like a verbal language in that sense.
h - move to the left CTL-f - change display forward a page
j - `jump' down a line CTL-b - change display back a page
k - move up a line CTL-d - change display down half a page
l - move to the right CTL-u - change display up half a page
- - same as k CTL-y - shift display down on screen
+ - same as j CTL-e - shift display up on screen
e - move to the end of a word z. - recenter display around cursor
w - move forward to the beginning of a word z- - recenter display so cursor is at top
b - move backward to the beginning of a word z+ - recenter display aso cursor is at bottom
$ - move to the end of the line zCR - recenter display so cursor is at top
0 - move to the beginning of the line 'm - move to the beginning of the line of mark m
^ - move to the beginning of the line `m - move to the location of mark m
G - move to the end of the file ) - move forward 1 sentence
H - move to the top of the display ( - move back 1 sentence
M - move to the middle of the display } - move forward 1 paragraph
L - move to the bottom of the display { - move back 1 paragraph
B - move back to previous blank space 20| - go to 20th character in the line
E - move ahead to next blank space CTL-L - clear and redraw
B - move back to previous blank space CR - same as j
CTL-G - print current location in the file :22 - move to line 22
6w - move forward 6 words
6b - move backward 6 words
8+ - move down 8 lines
etc.
Inserting and Replacing Text
o - open a new line above cursor(*) O - open a new line below cursor(*) i - insert text ahead of cursor(*) I - insert text at the beginning of the line(*) a - append text after the cursor(*) A - append text at the end of the line(*) c$ - change to end of the line (*) d$ - delete to end of the line C - same as c$ (*) D - same as d$ cG - change to end of the file (*) dG - delete to end of the file c0 - change to beginning of file (*) d0 - delete to beginning of file cc - change line (*) dd - delete line c'm - change from cursor through mark m (*) d'm - delete from cursor through mark m 3cc - change 3 lines (*) 3dd - delete 3 lines 8cw - change next 8 words (*) 8dw - delete next 8 words R - overwrite current line, starting at cursor(*) r - replace character at cursor s - substitute for character at cursor (*) 8s - substitute for next 8 characters (*) S - substitute for entire line (*) J - join two lines together . - repeats previous edit command xp - transpose two characters easESC - add a plural, and go back to command mode (*) - leaves you in insert mode until you hit ESC keyUndo [Important enough to have its own section (at least for me!)]
/where - search forward for the string 'where'
?where - search backward for the string 'where'
n - search in the same direction for the same string
N - search in the reverse direction for the same string
fc - search for the character 'c' in the current line
; - find the next occurance of the same character in the current line
, - same as ; but search backwards in the line
(f ; and , are not that useful in my opinion)
:abbr ph Pat Hartigan - The abbreviate command. Whenever you type 'ph' followed by a space
or punctuation in the file, vi will print 'Pat Hartigan'. Could be
useful I guess. Or annoying. Such definitions can be put into one's .exrc file.
Simple Substitutions
:w name - writes file 'name' :w! name - overwrites file 'name' :q - terminates editing session :q! - terminates editing session without storing changes :wq - writes changes and quits ZZ - same as :wq
mk - record current location as mark k (redefines any previous mark k) 'k - return to line of mark k `k - return to mark k d'k - delete to line of mark k d`k - delete to mark k c'k - change text to line of mark k c`k - change text to mark k "ay'd - yank text into buffer a from cursor through line of mark d CTL-A - increase the number in the file near the cursor by 1 CTL-X - decrease the number in the file near the cursor by 1Buffers, Cut and Paste
Note "a means `buffer a' yy - yank current line to unnamed buffer "j8yy - yank 8 lines into buffer j 19yy - yank next 19 lines to unnamed buffer "J8YY - append the next 8 lines into buffer j p - put unnamed buffer contents after cursor p - recover previous edit P - put unnamed buffer contents before cursor "1p - recover 2nd previous edit 19dd - delete next 19 lines, and put them in unnamed buffer "7p - recover 8th previous edit "bp - put the contents of buffer p into current file :11,14 ya w - yank lines 11 through 14 into buffer w :94 pu w - put contents of buffer w after line 94More Complex Searches and Substitutions, Colon Commands
Probably the most important advanced command is :g. It is powerful, very quick, and once you combine it with s and figure out the syntax, you will be flying through editing sessions. The price to pay is you need to spend time to learn its cryptic syntax. Well worth it.
Let's look at some s commands first, then combine g and s.
:2,8s/string1/string2/g
The syntax here is
: -- indicates that this is an ex command
2,8 -- a location within the document. In this case lines 2 through 8
using 2,$ would go from line 2 to the end of the file
.,5 would mean from the position of the cursor through line 5
.,'k would mean from the position of the cursor through mark k (which you set previously with m k)
s -- substitute. You are about to look for a string and replace that string with something else
/string1/ -- search for the string between the two /'s. In this case the string is 'string1'. If your
string contains /, you must escape them with a \. So, to search for '/home/user'
you would type /\/home\/user/. Same thing for other characters like ., $, ^, &, *, that the
editor would otherwise think have special meanings.
/string2/ -- If you find the first string, replace it with string2.
/g -- Adding the /g means that if string1 exists more than once on a given line, the editor will replace
all instances of string1 with string2. Otherwise it only replaces the first one it finds. Sometimes
replacing only the first occurrence of a string is helpful.
:.,'ms/this/that/g - replace `this' with `that' throughout file from current line thru mark m
:.,$s/this/that/g - replace `this' with `that' throughout file from current line thru the end
:33,224s/^/hh/ - insert the string 'hh' at the beginning of lines 33 through 224
:3,14s/$/hh/ - append the string 'hh' at the end of lines 3 through 14
Notice in these last two examples that the ^ and $ characters in the search string refer to the position
in the line, i.e., the beginning or end, while if they were immediately behind the colon they would
refer to the line number in the file. So, for example,
:.,$s/$/./
means
: -- ex command
.,$ -- from where the cursor is located to the end of the file
s -- substitute
/$/ -- look for the end of the line
/./ -- substitue a .
So the command adds . to the end of all lines from the cursor position to the end of the file. Similarly,
:.,0s/^/\^/
Puts the character ^ at the beginning of the line from the cursor position to the beginning of the file, while
:0,.s/\^/ /
replaces every ^ with a space from the beginning of the file, and
:0,$s/\///g
deletes all occurrences of / throughout an entire document
Now we are ready to use the g command. This is used for global substitutions.
It is quite similar to the above, except the syntax is just a bit different.
Consider
:g/ok/s//hi/g
:g/ -- indicates a global search. You will search for what is in between the next set of / /
/ok/ -- search for the string ok
// -- once you have found the string ok, you will now substitute for it. Note that
:g/ok/s//hi/g is identical to :g/ok/s/ok/hi/g so effectively the // is just a shorthand
because most of the time when you are searching for something you want to change it to
something else and with // you don't have to type the string again. But not always!
For example, maybe you want to change 123 to 456, but only on lines that have
the string ok in them. Then you would type :g/ok/s/123/456/g
/hi/ -- this is the string you are putting in as a replacement for ok.
/g -- indicates you want to replace all the ok in the file, even if there are more than one on a given line
Another example
:g/\/home\/me/s//\/r2\/you/g - replace /home/me with /r2/you throughout the file
Notice that since g is a global search, there are no line number specifications. If you want those
you will have to use the : and s commands as described above. Since there are no line specifications,
the variables . ^ $ and so on refer to positions within the line, not the line number in the file.
The use of & in substitutions
The & character has many uses, especially for creating data with columns. For more flexibility here
you can use awk. Essentially when you do
a search, the result is stored in a variable called &, which you can then reuse in that substitution.
For example,
:g/.*/s//mv \/home\/& ..\/&.copy/ does the following
:g -- the ex global command
/.*/ -- search for the string ., which means any character, followed by *, which means any string.
So the search string .* simply means 'everything'. Hence, the contents of the entire line are stored
in the variable &. The editor will work line by line, and replace the contents of & with each new line
/s/ -- you will be substituting something every time you find .*, that is, in each line
// -- shorthand for .* (see above), meaning that you will be substituting for the entire line. The contents of
the line are now stored in &.
/mv \/home\/& ..\/&.copy/ -- this looks complicated (impress your friends!) but it really isn't. Within the
first and last / lies the string you will put in for each line. If the input string is filename, the
replacement string would be
mv /home/filename ../filename.copy
As you can see, this will be very useful for making command scripts that you can run within the operating system,
within any coding environment that takes scripts like IDL or IRAF. The & variable also works with the s command,
so to do exactly the same thing but only from lines 10 to 20 type
:10,20s/.*/mv \/home\/& ..\/&.copy/Really fancy searches and substitutions On rare occasions it might be useful to not put the contents of the search string into a single variable &, but rather put one part of the search into /1, another into /2, and so on. Suppose you wanted to change a file as below:
try.dat --> cp try.dat ../dat/try.15.dat ok.dat --> cp ok.dat ../dat/ok.15.dat yes.file --> cp yes.file ../file/yes.15.fileYou really need to split the search string, because you want to use the part in front of the . (try, ok, yes) in multiple ways and the part after the . (dat, file) in a different way. This is done throughout the entire file in the following magical command (well, maybe not so magical by now)
:g/\(.*\.\)\(.*\)/s//cp \1\2 ..\/\2\/\115.\2/Oooh. Look at all those slashy characters, dots and stars. Even the sysadmin guy looking over your shoulder will be impressed. But it is really just syntax. Break it apart into pairs of \( \) which look like pairs of ( ) except they are escaped by a \. For each line, within the first pair of \( \) is stored the variable \1 which you will call later, within the second one \2 and so on. I don't think there is a limit. So let's break it apart
:g/ -- the global command of ex
\(.*\.\) -- the string .*\. goes into variable \1 What is this? Well, .* is any character followed by any
string, so just that would be the whole line. But you also need a \. which simply means the character .
It needs to be escaped with a \ because otherwise it is a wildcard that means any single character, which is what
the first . meant. So \(.*\.\) picks out "try." and puts it into \1, then "ok." into \1 then "yes." into \1
as it goes through the lines.
\(.*\) -- This one is pretty easy, between the \( and \) is .*, which means everything. So once it is done
putting things into \1, the editor dumps the entire rest of the line into \2. For the three lines in
our file it means "dat" in \2, then "dat" (again) in \2, then "file" in \2.
/s/ -- substitute every time you find the \1\2 string combination defined above
// -- replace the entire contents of what you just found
/cp \1\2 ..\/\2\/\115.\2/ -- with what is between the leading and trailing /. Let's just do the first line. In this
case \1="try." and \2="dat" (quotes are mine, not part of the variable). So \1\2 ..\/ translates into
try.dat ../ and /2\/\1 becomes dat/try and finally 15.\2 becomes 15.dat So the result is that
try.dat is replaced by cp try.dat ../dat/try.15.dat
I would not type in all of that for a 3-line file. I would probably do :g/.*/s//cp & ..\/dat\/&/ which gets me close,
and then insert the 15 (by moving the cursor with jhlk, typing i15Global searches followed by print, move, or delete
You don't have to substitute once you've found something with :g -- you can also delete the line. Simply replace the s with a d and you are done. So to delete all lines in a file that contain the string "ok" you would type
:g/ok/dTo delete blank lines type :g/^$/d
:g/ok/pThis command flips the order of lines in a file (first line to last and vice-versa) using the m command from ex. It works by moving the current line to the top of the file, and when it has finished going through the entire file, the order of the lines has flipped.
:g/.*/m0File Manipulation
:e newfile - begin editing 'newfile' without exiting vi (keeps buffer contents) :r newfile - read contents of `newfile' into current file vi file* - sequentially edit file1, file2, file3, etc. :n - edit the next file in the sequence :!pwd - do the Unix command 'pwd' and return to viMacros, Special Characters
Suppose you want to delete two words, jump down 3 lines, move back a word,
and then do this process over and over within a file. Define these commands to
an unused vi key (e.g. v) by typing
:map v 2dw3jb
then keep the v key depressed until you are done. To insert the
string 'hi', a CR, the string 'there', then delete the second to last word
in the next line and skip 2 lines, define (don't type brackets - [ESC] means type the escape key)
:map v ihi[CTL-V][CR]there[CTL-V][ESC]$2bdw2j
Want to run a whole bunch of vi commands on a bunch of files from a script? Store the commands you want in a file. When creating the command file with vi, remember that to store characters like ESC and CTL you need to type CTL-V first. Once the commands are in a file, edit your main document and :r macrofile (usually a single line), and then type "add which will delete the macro from your document and store it in buffer a. To execute the macro type @macrofile or 5@macrofile if you want to do it 5 times. For multiple files or other edits you can use sed, which has basically the same syntax as vi.
Examples of some potentially useful settings. The inverse of `number' is `nonumber', of `nowrapscan' is 'wrapscan', etc.
:set all - view all current settings :set nowrapscan - do not wrap around file when looking for a string :set number - add line numbers to left of file :set noautoindent - do not automatically indent the file :set report=0 - always report at bottom when any number of lines are yanked :set ignorecase - treat capital and small letters the same when searching
If this doesn't work, you can try to reset your TERM variable from the Unix prompt. When telnetting in from a PC the first thing I do is type 'setenv TERM xterms' which seems to make everything work right. Another possibility is to use 'setenv TERM vt100', though I found that vi doesn't deal with lines > 80 chars or refresh the screen right in insert mode (you need to type a lot of 'z.' to redraw the screen) for this setting. At the Unix prompt you can fix minor annoyances like the delete key not being set right by typing 'stty ERASE {key}' where {key} is what you want for an erase key. You might also need to type 'stty echoe' to have your screen actually remove the characters you erased. Within vi you can always limit the size of your vi window to 15 lines if desired by typing 'z15'.
Back to Hartigan's Home Page