A quick reference for
vi and ex

vi has three modes

  1. command
  2. insert
  3. ex aka command-line
vi starts in command mode where you can issue commands to move the cursor, cut, copy or modify text.
Some commands change mode, for example i, a change to insert mode.
When in insert mode characters you type are entered into the file. Pressing terminates input and returns to command mode .

This is the biggest problem that most people have with vi. Pressing the same key has different effects depending on the mode.
For example, in command mode pressing i changes to insert mode. At this point pressing i inserts the character i into the file.

Typing a : (colon) puts you in ex mode where you can use powerful ex commands which frequently operate on a range of lines like g, s, v, ! etc.

Enter the ex command :set showmode to have vi display -- INSERT -- on the bottom line of the display when in insert mode

                   :   ex   ━━━━━━━━━━━━━━━━━━━┐
                    command                     ┃
                   example: %s/x/y/g            ┃
                   vi  commands  ━━>━━━━━━━━━━━━⊣
                        x,w,$ …                  ⎮
         ^         Ï  enter characters  ━━━━━━┐
         ⎮              insert              ⎮     ⎮
         ⎮              mode                ⎮     ⎮
         ⎮                                  ⎮     ⎮
         <━━━━━━━━━━━━<━━━━━━━━━━━━━━━━━━━━━┘     ⎮

Ï is any of i,I (insert) a,A (append) c (change) o,O (open)

Back to top

Quick help

( Commands and combinations to get you started )

moving around
cursor by character
notice the position on the keyboard

orientation in this document is meant to SHOW how actions occur

left h  l right
by line
- first column previous line
0 zeroth column on line end of line$
     ^ first character on current line (other than tab or space)
+ first column on next
[n]G Go to line n
by screen
H move cursor to top of screen
z- position line with cursor at bottom of screen
^y scroll down 1 line
^b scroll backward towards the top
 ^uup half screen
z.position line with cursor at middle of screen
M move cursor to Middle of screen
 ^dscroll down half screen
^fscroll forward one screen
^e scroll 1 line up
z[enter]   position line with cursor at top of screen
L move cursor to bottom of screen
miscellaneous movement
   b backAwordw nextWord
B back-a-WORD.
(punctuation, including <, is part of WORD)
W next-WORD.
e toEndOfWord
E to-end-of-WORD
( previous sentence ) next
{ previous paragraph }next
[[ previous section   ]]next
( depends on settings for what constitutes a "section" and "paragraph" )
Fd back to d fG forward to G
 Td back to character after d  tG forward to character before G
marking position
mz mark current position with z
`z move cursor to mark z
inserting text
I Insert at beginning-of-line Append at end-of-line A
insert before cursor   i a   append after cursor 
O Open above cursor
o open line below cursor
[esc] terminate insert mode
deleting text
delete character under cursor x
dw delete word D delete from cursor to end of line
Replacing / Changing text
replace character under cursor r Rreplace word
cwchange a word CChange the rest of the line

Back to top

Syntax of commands

Most commands in have the form:
[n] operator

5x delete 5 characters
3fG forward to third G on line
2tO forward to character before second O on line
3Tc backward to after the third c
20j move cursor down 20 lines
5Hmove cursor 5 lines from top of screen
5rx replace next 5 characters with x
5$ move to end of 5th line down (line 1 is current)

Editing commands c, d, y have the form
      [n] operator [m] object
An object is a character, word, line, sentence etc.

c begin a change d begin a delete y begin a yank

cc, dd, yy operate on the current line, i.e. copying, deleting or yanking the current line.
If both n and m are specified the effect is n * m, that is n multiplied by m.

cw change word   c$ change to end of current line
5dd delete next five lines   d5G delete to line 5
dG delete to end of file   de delete to end of word
d^ delete to beginning of current line   yy yank current line
y'z yank to line marked with z   yL yank to bottom of screen

Commands are not echoed except the following which are echoed on the status line.

/    search forward ? search backward
: invoke an ex command
! invoke a OS command that takes as its input,
an object in the buffer, and replaces it with output from the command

The above commands are completed by pressing enter.

A buffer refers to the file as it's kept in memory.

<, >, and ! can also be combined with a movement command like c, d, and y

>> indent current line one shiftwidth
5<< outdent 5 lines starting with current
/hello search forward for word 'hello'

vi command keys in alphabetical order

^B stands for <control-B>
If there is an n in the count column then the command can be preceded by a number and the command then is executed count times.
If the command is an editing command such as a or i, press [esc] for the execution to occur count times. See example in
Part I/a.
A word consists of [a-zA-Z_] ( ex: these are small_words )
and a WORD consists of [a-zA-Z_] plus punctuation delimited by whitespace (ex: these, are. BIG_WORDS! )

na append after cursor nA append at end-of-line (same as $a)  ^A unused
nb back up a word nB back up a WORD n^B scroll up a screen
nc begin a change (combine with movement command) nC change line from cursor to end-of-line (same as c$)  ^C abort current ex command
in insert mode : end insert mode
nd begin a delete (combine with movement command) nD delete from cursor to end-of-line (same as d$) n^D scroll down a half screen
in insert mode : back up one shiftwidth
ne goto end-of-word nE goto end-of-WORD n^E scroll a more line at bottom of screen
nf forward to next typed character nF backward to next typed character n^F scroll down a screen
 g unused n G goto line n; default is end-of-file  ^G print file info on status line (bottom of screen)
nh cursor left nH goto Home of screen or
n lines from top of screen
n^H cursor left
in insert mode : backspace
ni insert before cursor nI insert at beginning-of-line (same as _i)  ^I unused
in insert mode : tab key
nj cursor down nJ join current line with next n^J cursor down
in insert mode : same as enter
nk cursor up  K unused  ^K unused
nl cursor right (hjkl) nL goto Last line of screen
n will place cursor that many lines from bottom of screen
 ^L redraw screen, usually
 m mark current cursor position with character typed (a-z)  M goto middle of screen n^M goto first character on next line
in insert mode : same as enter key
 n next search match  N Next search match BUT in opposite direction n^N cursor down
nO open a new line above the cursor no open a new line below the cursor  ^O unused
np put yanked or deleted text after or below cursor nP put yanked or deleted text before or above cursor n^P cursor up
 q unused  Q quit vi, invoke ex (not very useful) return with vi  ^Q unused (some terminals, stop data flow)
nr change character under cursor to character typed nR replace characters (overwrite mode)  ^R redraw screen, usually
ns substitute characters under cursor to ones typed nS substitute entire line  ^S unused (on some terminals, resume data flow)
nt forward to before next character typed nT backward to after next character typed  ^T goto previous tag
in insert mode : move right one shiftwidth
 u undo last change  U restore current line n^U scroll screen up a half screen
in insert mode : delete back to start of insert (depends on terminal settings)
 v unused  V unused  ^V unused
in insert mode : quote next character
nw forward a word nW forward a WORD  ^W unused
in insert mode : back up to beginning of word (depends on terminal settings)
nx delete character under cursor nn delete back a character  ^X unused
ny begin a yank (combine with movement command) nY yank current line (same as yy) (map it to y$ to be consistent with D and C) n^Y show more lines at top of screen i.e. scroll back
 zenter reposition line with cursor to top of screen  z. reposition line with cursor to middle of screen  z- reposition line with cursor to bottom of screen
 ZZ exit vi, write changes
 ^Z suspend vi on systems that have job control (depends on terminal settings)  ^@ unused
 [esc] terminate insert mode  ^\ unused?
 ^] goto tag under cursor
 ^^ edit alternate file  ^_ unused?  ^? unused? delete key?
nspace cursor right
 ! filter program through external filter, requires an object to work on
(combine with movement command) (press enter to execute)
 " use register for next delete, yank or put, registers are (a-zA-Z0-9)  # unused?
 0 goto beginning-of-line n$ goto end-of-line
 % goto matching bracket ( ) [ ] { }
 . repeat previous command  & repeat last substitute
 ' to first non-blank character on line with mark (a-z)
n( beginning of next sentence
n) beginning of current sentence
(sentence is delimited by ., !, ? and followed by at least one space)
 * unused?
n+ down one line to first non-blank character (j_)
n; repeat f, F, t, T commands n, repeat f, F, t, T commands in reverse direction
n- up one line to first non-blank character (k_)
 / search forward for text entered
(repeat previous search if no argument supplied) (press enter to execute)
 ? search backward for text entered
(repeat previous search backward if no argument supplied) (press enter to execute)
 : enter an ex command (press enter to execute)
n< begin a shift left (combine with movement command) n> begin a shift right  = unused
(unless in lisp mode in which case it formats to standard lisp formatting)
 @ execute a register (0-9a-z".)  
n[ beginning of current section (as delimited by the sect= option)  \ unused
n]] beginning of next section (as delimited by the sect= option)
 ^ goto first non-blank character on line
 ` goto mark (a-z)
n_ goto first non-blank character on line
n{ beginning of current paragraph
(as delimited by a blank line or the para= option)
n| goto column n , default is beginning-of-line
n} beginning of next paragraph (as delimited by a blank line or the para= option)
n~ change case of character under cursor

vi commands can be remapped.

Use :map to list the current ones.
Here are some useful ones.
( note ^M is the control sequence for [enter])

map ^N :n^M   ^N finds the next match and without pressing [enter]
map ^P :rew^M   ^P qq begin recording
map  Y y$   Y qq
map  g 1Gi   g goes line 1 for inserting

Control characters will have to be quoted with ^V, that is <control-V>
Alphabetical list of commans shows unused

Back to top

ex editor

i.e. line ranges
0 (zero) beginning of file $ end-of-file
% stands for filename,
i.e. the entire file
1,$ all lines in file
. current line
/pattern/ forward to line matching pattern
.,/pattern/ forward to line matching pattern .,/table/ current line through
the line containing table
?pattern?   backward to line matching pattern
x,y lines x through y 3,8  lines 3 through 8
x;y lines x through y,
current line reset to x
n absolute line number n
x-n n lines before x x+n n lines after x
-[n] n lines back (default one) +[n] n lines ahead (default one)
'x line marked with x
'' previous mark ( two apostrophes)
# alternate file

Back to top

ex commands and their abbreviations

abbreviate move tag
append next unabbreviate
args number # undo
change open unmap
chdir chd preserve version
copy t print visual
delete put write
edit quit xit
file read yank
global recover (window) z
insert rewind (escape to OS) !
join set (lshift) <
list shell (rshift) >
map source (line number) =
mark k substitute s & ~ (execute buffer) * @

Back to top

ex commands

[ ] refers to optional parameters

range   aka address[,address] specifies the optional range of affected lines.

1,3s/A/a/ affects lines 1 through 3, substituting A for a
.,$d from this line to the ending line delete

The default for address is the current line,
except for g, g! , v, w; these the default is the entire file.

range substitute[/pattern/replacement/][options][count] substitute pattern with replacement.
count number of lines to operate on.
c prompt for confirmation
g all occurances on line
p print last line on which substitution was made

If pattern and replacement are omitted repeat last substitution.


All lines, substitute hello or Hello with hi, all ocurrences

Upcase unix on next 10 lines

turn the first letter of all words to uppercase

Substitute all occurances of int, before the main, with long

undo undo changes made by last editing command.
xit exit file. save changes.
address append[!]
append text at address . ! switches autoindent.
address insert[!]
insert text at line before address.
! switches autoindent.
range change[!]
replace lines with text.
! switches autoindent.
range copy destination copy lines from address to destination .
example: copy lines 1 to to 10 to below line 50
range t destination
range delete [buffer][count] delete lines in range , if buffer is specified save lines to buffer. count specifies the number of lines to delete starting with range .
:/include/,/main/d delete lines between include and main inclusive
:/include/+,/main/-d as above but not including include nor main
:3d delete line 3
:d3 delete 3 lines starting with current
:.,$d a delete to end-of-file from current line into buffer a
:d a3 delete next three lines starting with current into buffer a
edit[!] [+n] [file] begin editing file.
! will discard changes to current file.
n specifies line to begin editing file (default 1).
eg. :e file edit file
:e # edit previous file
file [filename] change name of file to filename.
without argument print current filename.
:f %.new appends .new to current filename,
renaming file to file.new
range global [!]/pattern/[commands] execute commands on lines that contain pattern,
if address is specified within the address range.
! execute on lines not containing pattern.
default for commands is print .
:g/\#include/d delete all lines that have include directives
:g!/\#define/p print lines that are not define statements
:g/^\/\*/p print lines that start with /* comment
:g/^^I*$/d delete empty lines as well as lines with only tabs or spaces
:g/strcmp/d5 delete 5 lines, wherever strcmp occurs.
range join[!][count] join lines in specified range.
! preserves white space.
eg.:1,5j ! join lines 1 to 5, preserve white space
range k[char] synonymn for mark,
char can follow k with no intervening space.
range list[count] print lines so that tabs show as ^I
and end-of-lines are marked with $.
map[!] [char commands] Define a keyboard macro for named char that is a synonymn for commands.
! will create a mapping for input mode.
With no arguments, print mapped keys.
eg. :map ^N :n^M (to enter a control character type ^V followed by the control character)
unmap[!] char remove char from keyboard macros. ! remove macros for input mode.
abbreviate string text define string that when typed is translated to text.
if string text not specified, list abbreviations.
abbreviations are usually put into your .exrc file
examples: correct spelling mistakes !!
        :ab charcater character
        :ab teh the
        :ab hvae have

      :ab   (shows all current abbreviations)
unabbreviate word remove word from list of abbreviations.
range mark c mark lines with c. c is a single lowercase letter. example:
:ma z mark line with z
:'z return to line with mark z
range move destination move lines specified by range to destination . example:
:.,/ include /m / string /
current line, thru line containing include are moved below line with string
next[!] [[+commands] filelist] edit next file from argument list.
if filelist is provided, replace argument list with filelist.
! will discard changes to current file.
range number[count]
range #[count]
print lines specified by range , precede each line by its line number.
count specifies the number of lines to print.
range open[/pattern/] enter vi's open mode with lines specified by range , or at lines containing pattern.
preserve save current buffer as if the system had crashed
range print[count] print lines specified by range . count is the number of lines to print. eg. :304;+5p print five lines starting with 100, reset current line to 100
range put [buffer] restore lines that were previously deleted or yanked and put them after current line. put line from buffer if specified.
quit[!] ! force discard changes to file.
range read file copy text from file on the line below the specified by address. eg. :0r data read in file "data" at top of file
address read !command read the output of command into file after line specified by address . eg. :$r !ls -aFC run "ls" and read in its output into the end of the file
recover [file] recover file from system save area.
rewind[!] rewind argument list to first argument. ! discards changes to current file.
set parm1 parm2 set value to an option with each parm. if no parm is supplied print all changed options.
for boolean options parm is phrased as option or nooption, other options are option=value. all will print all available options.
set commands are usually put into your .exrc
eg. :se autowrite tabstop=4 autoindent shiftwidth=4 wrapmargin=5
:se all print all available options
shell create a new shell. resume editing when shell exits.
source file
    read and execute ex commands from file  
eg. so ~/old.exrc
tag tag switch to file containing tag.
eg. :!ctags *.c run ctags on all .c files in directory
:ta func switch to file containing func, put cursor on it
range v/pattern/[commands] synonymn for global!
eg. :v/./,/./-j join empty lines to have only single empty line between lines of text
version version of editor.
range vi [type][count] enter visual mode at line specified by address. exit with Q. count
specifies initial window size.
. place line in center of window
- place line at bottom of window
^ print previous window
vi [+n] file begin editing file in visual mode at line n.
range write[!] [[>>] file] write lines specified by address to file. >> append .
with no address, write all . ! forces the write.
eg. :1,25w new_file write lines 1 to 25 to "new_file"
:50,$w >> new_file append line 50 to end of file to new_file
range w !command write lines specified by address to command.
wq[!] write lines specified by address to file and quit.
! forces the write
range yank [buffer][count] place lines specified by address in buffer char.
count is the number of lines to yank starting with address.
eg. :20,100ya z yank lines 20 to 100 into buffer z
range z[type][count] repaint window. count is the number of lines to display starting with address.
+ current line at top of window(default)
. center of window
= place line in center of window. leave line as current line.
- bottom of window
^ print previous window
[esc] range ![command] execute command. if address is specified apply lines from address as input to command, and replace lines with output.
eg. :!ls -aFC run ls, will not read output into file
:0!ls -aFC run ls, read in its output to beginning of file
:11,35!sort -fd sort lines from 11 to 35
:%!spell -b run the spellchecker on entire file
range = print line number of matching address. with no address print line number of last line.
range <[count]
range >[count]
shift lines left(<) or right(>). count specifies the number of lines to shift starting with address.
eg. :1,9> indent lines 1 through 9 one shiftwidth
address print line specified by address.
return print next line.
range &[options][count] repeat previous substitution. count specifies the number of lines to substitute on starting with address.
eg. :s/msdos/UNIX substitute msdos with UNIX
:g/OS/& redo substitutions on all lines with "OS"
range ~[count] replace previous regular expression with the previous replacement from substitute.
execute named buffer
args print filename arguments.
cd [path] without path change to home directory, with path change to path

The following can be used as addresses in ex, as well as in commands :g, :s, :v, and in the vi commands ?, and /

Back to top

REGular EXpression search and substitute

vim uses a slight varient of Regular expressions
. any single character except newline
* 0 or more of the single atom immediately preceding
^ beginning-of-line if at start of expression
$ end-of-line if at end of expression
[ ] anything in [ ] character class
[^] anything not in [ ]
\( \)  [esc] store pattern for later replay
\< [esc] following characters at beginning of word
\> preceding characters at end of word
\ escape following special character (ex:use \. to match a dot )
\n reuse previous pattern, n is a number between 1 and 9 eg. \1
& reuse previous search pattern
~ reuse previous replacement pattern
\u change character to upper case \U change characters to upper case
\l change character to lower case \L change characters to lower case
\e turn off previous \u or \l \E turn off previous \U or \L

Perl Perl
^Perl Perl at beginning-of-line
Perl$ Perl at end-of-line
^Perl$ Perl as the only word on line
^$ the empty line
^..*$ a line with at least one character
.* any string of characters including none
^[ ^I]*$ as above but line can also contain spaces and/or tabs(^I)
[pP]erl perl or Perl
[aA][nN] an, aN, An, AN
p[aeiou]g second letter is a vowel
i[^aeiou]g second letter is not a vowel
p.g second letter is anything
^....$ a line with exactly four characters
^\. any line beginning with a dot
^\.[0-9a-z] same with a lowercase letter or digit following
^[^\.] any line that does not begin with a dot
;$ line ending with a semicolon
figs* fig, figs, figss, figsss ...
[a-z][a-z]* one or more lowercase letters
[a-zA-Z] lower OR uppercase letter
[^0-9a-zA-Z] any symbol (not a letter or number)
\<the the, theater, then
the\> the, breathe
\<the\> the
usefull operations for the entire file
:%s/\<./\u&/g turn the first letter of all words to uppercase
:%s/.*/\L&/ turn entire file to lowercase
:%s/<<>>^>]*>//g remove strings that start with a less than sign and end with a greater than sign
(html tags)
.( a what?? qq ), ^, &, $ must be preceded by a \ to make literal when magic is on.
* must be preceded by a \ under certain circumstances qq which are:..... although it never hurts to precede it with a backslash whenever you mean a * not its regexp meaning.
% and # should also be escaped as they mean current and alternate file to ex.

Regular expressions only work in a s/pattern/replacement/ for the pattern and not the replacement

My RE isn't matching/deleting what I want it to. (Or, "Greedy vs. stingy pattern matching")

The two most common causes for this problem are:

  1. misusing the . metacharacter, and
  2. misusing the * metacharacter.
The RE .* is designed to be "greedy" (i.e., matching as many characters as possible). Sometimes users need an expression which is "stingy," matching the shortest possible string.
  1. On single-line patterns, the . metacharacter matches any single character on the line. (. cannot match the newline at the end of the line because the newline is removed when the line is put into the pattern space; sed adds a newline when the pattern space is output.)
    On multi-line patterns obtained with the 'N' or 'G' commands, . will match a newline in the middle of the pattern space. If there are 3 lines in the pattern space, s/.*// will delete all 3 lines, not just the first one (leaving 1 blank line, since the trailing newline is added to the output).

    Normal misuse of . occurs in trying to match a word or bounded field, and forgetting that . will also cross the field limits. Suppose you want to delete the first word in braces:

    echo {one} {two} {three} | sed 's/{.*}/{}/' # fails
    echo {one} {two} {three} | sed 's/{[^}]*}/{}/' # succeeds
    s/{.*}/{}/ is not the solution, since the regex . will match any character, including the close braces.
    Replace the . with [^}], which specifies a negated character set [^...] containing anything other than a right brace.
    s/{one}/{}/ would also solve our question, but to illustrate the use of the negated character set: [^anything-but-this].

    A negated character set should be used for matching words between quote marks,
    for fields separated by commas, and so on.

  2. The * metacharacter represents zero or more instances of the previous expression. This looks for the leftmost possible match
    echo foo | sed 's/o*/EEE/'
    will generate EEEfoo, not fEEE because /o*/ matches the null string at the beginning of the word.

    After finding the leftmost possible match, the * is GREEDY; it always tries to match the longest possible string. When two or three instances of .* occur in the same RE, the leftmost instance will grab the most characters. Consider this example, which uses grouping \(...\) to save patterns:

    echo bar bat bay bet bit | sed s/^.*\(b.*\)/\1/'
    What will be displayed is bit because the leftmost .* took the longest possible match.
    eemember ',this rule: "leftmost match, longest possible string, zero also matches." see also sedFAQ

    from http://www.vmunix.com/~gabor/vi.html
    Originally this file was turned into HTML format by Karlon West.
    I updated it and fixed some errors. This helpfile is based on a helpfile that I wrote (with the help of various man pages from Linux, BSD, DEC Unix, HP-UX) in text format in 1995.
    It was further "adjusted" by Dennis German

    Please e-mail me if you find any errors.