When coming to grips with the vi editor—either for the first time or as a regular user—most people tend to have a grasp of the core command set that allows them to perform those functions they use most regularly: navigating or saving a file; inserting, updating, deleting, or searching for data; or quitting without saving changes.
However, the vi editor is extremely powerful and rich in features and functionality. Even after many years of use, you can still uncover new commands that you didn't realize existed. The commands covered in this article are amongst those less well known, but they can help you to work smarter by short-cutting existing methods you may use or allowing you to do something that you never realized you could do with vi.
Before we start just a recap on the two modes of vi: command and insert. Command mode allows the user to execute commands to modify text, navigate around the file or control your vi session in some way. Insert mode puts anything you type into the current file in your vi session. When you start vi you start in command mode. Once in insert mode you can switch back to command mode by hitting the Escape key. Hitting the Escape key whilst in command mode leaves you in command mode. All of the commands covered in this article should be executed from command mode.
Turn line numbering on and off
The vi editor has a number of options that determine the look and feel of
an editing session. To change any session settings in vi, you use the
:set command. To display a list of the options and
settings, use the :set all command.
One of the options you can set is number, which turns
line numbering on and off (see Listing 1).
Listing 1. Before line numbering is turned on
# # Internet host table # ::1 localhost 127.0.0.1 localhost loghost 192.168.0.6 centos5 192.168.0.10 appserv 192.168.0.11 webserv 192.168.0.12 test 192.168.0.5 solaris10 # Added by DHCP ~ ~ ~ :set number |
This command instructs vi to display a line number against each record in the file you
are currently editing. After putting vi into command mode, you can type
:set number and press Enter to turn line numbering
on (see Listing 2).
Listing 2. Line numbering turned on
1 #
2 # Internet host table
3 #
4 ::1 localhost
5 127.0.0.1 localhost loghost
6 192.168.0.6 centos5
7 192.168.0.10 appserv
8 192.168.0.11 webserv
9 192.168.0.12 test
10 192.168.0.5 solaris10 # Added by DHCP
~
~
~
:set number
|
You can use the :set nonumber command to turn
line numbering off. You can also use shorthand versions of this and the
:set number command—namely,
:set nu and :set nonu.
Having line numbers displayed can be particularly useful when you need to quickly calculate the number of lines you want to process with a vi function. This is especially true when the number of lines is long and may span several screens, or you know the range of lines you want to process but need to find the start and end line numbers that you'll use in the appropriate vi command.
If you want to display line numbers every time you enter a vi session, add the line
set number to the .exrc file in your home directory.
When writing code in certain programming languages, indentation is an important
part of the style to ensure that the code is more readable. You can set
up the vi editor to automatically indent to adhere to a language-specific style
when necessary. You use autoindent to turn automatic
indenting on or off (see Listing 3).
Listing 3. Turning automatic indentation on
#!/bin/ksh
#
#
for file in /etc/*
do
if [[ -f ${file} ]] ; then
echo "${file} is a file"
~
~
~
~
~
:set autoindent
|
From this point on, if you use leading spaces or tabs in a line, subsequent new
lines will be indented to the same place. With vi in command mode, type
:set autoindent, then press Enter to turn on automatic
indenting. Set the level of indentation by setting shiftwidth.
For example, to set each indentation to four spaces, use
:set shiftwidth=4 (see Listing 4).
Listing 4. Setting the indentation level
#!/bin/ksh
#
#
for file in /etc/*
do
if [[ -f ${file} ]] ; then
echo "${file} is a file"
elif [[ -d ${file} ]] ; then
echo "${file} is a directory"
fi
done
~
~
:set shiftwidth=4
|
While in command mode, you can use the >>
command to add a level of indentation to an existing line or the
<< command to remove a level. Precede these
commands with an integer to add or remove an indentation level across multiple
lines. For example, with the cursor at the start of line 6 in Listing 4
and after entering command mode, type 5>> to
add an indentation level to the next five lines. Listing 5 shows
the result.
Listing 5. Indenting a block of lines
#!/bin/ksh
#
#
for file in /etc/*
do
if [[ -f ${file} ]] ; then
echo "${file} is a file"
elif [[ -d ${file} ]] ; then
echo "${file} is a directory"
fi
done
~
~
|
You can use the :set noautoindent command to turn
automatic indenting off. Shorthand versions of this and the
autoindent command are also available—namely,
:set ai and :set noai.
You can also turn indentation on and set the indentation level in one command by
using :set ai sw=4.
If you want to enable automatic indentation and set the indentation level to four
spaces every time you start a vi session, add the line set ai sw=4
to the .exrc file in your home directory.
As you would expect, pattern matching on searches in UNIX® is case sensitive.
However, if you want vi to ignore case sensitivity, you can use the
:set ignorecase command. Turn case sensitivity back
on using :set noignorecase. You can also use shorthand
versions (:set ic and :set noic).
If you want to ignore case sensitivity on searches every time you enter a vi session,
you can add the line set ignorecase to the .exrc file
in your home directory.
You can search for strings in vi using the / command,
specifying the pattern to match either as a literal string or as a regular expression.
For example, to search for the word echo in a file, enter command mode,
type /echo, and then press Enter. This command would
find the first word on line 3 in the file shown in Listing 6.
Listing 6. Compound searches
1 #!/bin/ksh
2 #
3 echo "Starting"
4 file=${1}
5
6 echo ${file}
7
8 if [[ ${file} = 1 ]] ; then
9 ((file=${file}+1))
10 echo "Adding one gives " \
11 ${file}
12 fi
13 echo "Ending"
14 exit
~
~
|
You can use a simple regular expression to specify that you want to find a line
containing one word followed by another. For example, to find the first line
containing the string echo followed by zero or more
characters followed by the string file, you would use
/echo.*file. In the file shown in Listing 6,
this command would find the first word on line 6.
However, this command will only find matches where both strings exist on the same
line. If you want to search for the first occurrence of a pattern or string where it
follows another regardless of whether both patterns or strings exist on the same
line, you can use a compound search by specifying both search commands separated
by a semi-colon (;). For example, to search for the first
occurrence of the string echo where it follows the string
{file}+1, you would use /{file}+1/;/echo/.
In the file shown in Listing 6, this command would find the first
word on line 10.
Compound searches are particularly useful when you are searching through code for the existence of a command that specifically follows another—for example, where a function is called after a particular variable is set.
When searching for patterns to replace within a file, you can instruct vi to save any
patterns that it matches into a buffer, which can then be replayed in substitutions
using a buffer reference number. You do this by enclosing the pattern within
\( and \), which instructs vi
to save the pattern into a numbered buffer (1 to 9). You can then reference these
buffers in substitutions using the buffer references \1
to \9.
For example, to search the file in Listing 7 for lines starting with
the word Martin and for each occurrence to add the prefix Mr
and the suffix Wicks, enter command mode, type the vi command
:%s/^\(Martin\)/Mr \1 Wicks/g, and then press Enter.
Listing 7. Replaying search patterns (before)
Martin is an IT consultant. Martin likes snowboarding and mountain biking. Martin has worked on UNIX systems for over 15 years. Martin also worked for many years before that on mainframes. Martin lives in London. ~ ~ ~ ~ :%s/^\(Martin\)/Mr \1 Wicks/g |
Here's a breakdown of the command into its components:
:%s- Instructs vi to perform a substitution./- Pattern separator.^\(Martin\)- Look for lines starting with the stringMartin, and save the string in buffer 1./- Pattern separator.Mr \1 Wicks- Substitute the string located with the stringMr, followed by the contents of buffer 1 followed by the stringWicks./- Pattern separator.g- Global change (that is, change every occurrence on every line matched).
You can use the buffer reference in both the search and in the substitution string.
The resulting changes are shown in Listing 8.
Listing 8. Replaying search patterns (after)
Mr Martin Wicks is an IT consultant. Martin likes snowboarding and mountain biking. Martin has worked on UNIX systems for over 15 years. Martin also worked for many years before that on mainframes. Mr Martin Wicks lives in London. ~ ~ ~ ~ :%s/^\(Martin\)/Mr \1 Wicks/g |
You can tell vi to place a bookmark at a point in a file by pressing the M key followed by another alphabetic character that denotes the
bookmark reference. Therefore, you have up to 26 bookmarks named a
to z. To return to the previous bookmark, press the back tick (`) followed by the bookmark reference
alphabetic character.
For example, after pressing the MA keys, you would save the current
cursor position into a bookmark named a. Whenever you want to return
to that cursor position later in the editing session, you simply press the `A keys. To flip between the current bookmark and the previous one, you can
use the double back tick (``) command sequence.
Find, update, find next, repeat
One of the most useful Search/Replace features of the vi editor is the ability to find a string matching a pattern, update it, and then repeat the same search for the next occurrence and optionally repeat the update against it, much like the Find Next/Replace functions found in Microsoft® Word.
You probably already know that you can search for string patterns in vi by entering
command mode, typing /search_pattern
(where search_pattern is a string or regular expression), and then
pressing Enter. Doing so takes you to the first occurrence of a string matching the
pattern specified. From here, you can perform whatever operation you want on the
located text. For example, pressing the C and W keys followed
by more text changes the located string to another word.
To quickly locate the next occurrence of a matching pattern, you press the N key. When the next match is found, you can optionally use the period
key (.) to repeat the last text operation at this
location, such as the change word (cw) function used
in the previous example. You can then continue to find further matches
(n) and optionally repeat the text operation
(.) using these keys in much the same way you would
use the Find Next and Replace functions in Word.
You can switch the case of the alpha character underneath your cursor in vi the tilde key (~). Doing so
shifts from lowercase to uppercase and vice versa. Holding down the key rolls over
each character in the line, flipping the case of any alpha characters the editor
comes across. You can enter a numeric character prior to the tilde to denote how
many alpha characters you want to change.
You probably know that you can execute commands in a shell within vi by typing :!command, where
command is the UNIX command that you want to execute—for
example, :!pwd to show the present working directory
your editing session is in—and then pressing Enter.
However, you can also send a section of your file as the standard input to a UNIX
command of your choice and have the same section in your editing buffer replaced
by the resulting output. For example, if you wanted to sort the entire file shown
in Listing 9 while remaining in the vi session, you would type :1,$!sort to instruct vi to pass lines 1
through the end of the file ($) into the
sort command, replacing the specified section with the
output, and then press Enter.
Listing 9. Sorting a file inside the vi session (before sort)
5 4 3 2 7 6 5 4 8 9 6 3 1 3 4 ~ ~ :1,$!sort |
Listing 10 shows the resulting output from the sort
operation.
Listing 10. Sorting a file inside the vi session (after sort)
1 2 3 3 3 4 4 4 5 5 6 6 7 8 9 ~ ~ :1,$!sort |
Alternatively, you can prefix the shell command with the number of lines you want it
to operate on from the current cursor. To do so type a numeric
character specifying the number of lines followed by double exclamation marks
(!!) followed by the UNIX command.
For example, with the cursor at the start of line 4 in Listing 9, you would type:
4!!awk '{print "New text",$0}'
|
and press Enter to prefix lines 4 through 7 inclusive with the text New text,
as shown in Listing 11.
Listing 11. Prefixing a block of lines with new text
5
4
3
New text 2
New text 7
New text 6
New text 5
4
8
9
6
3
1
3
4
~
~
!awk '{print "New text",$0}'
|
You can string UNIX commands together using the pipe separator
(|) to create complex and powerful filtering within
your vi session. For example, to replace the contents of the file in the editing
buffer of your current vi session with the first white space-delimited field of
each line, sorted into ascending order and translated to uppercase, you would enter
the following line:
:1,$!awk '{print $1}' | sort | tr [:lower:] [:upper:]
|
You can save sections of a file you're currently editing by entering :start,endw file,
where start is the first line in the current file from which you want to
save, end is the last line that you want to save to,
w denotes that you want to write to another file (or
overwrite an existing file), and file is the name of the file to which you
want to save the specified section. You can use the $
notation for the last line to specify to the end of the file and double greater-than
symbols (>>) after the w
to indicate that you want to append to rather than overwrite the file. The example in
Listing 12 shows lines 6 to 9, inclusive, being appended to a file
called /tmp/newfile.
Listing 12. Saving a section of a file to another, appending rather than overwriting it
1 #
2 # Internet host table
3 #
4 ::1 localhost
5 127.0.0.1 localhost loghost
6 192.168.0.6 centos5
7 192.168.0.10 appserv
8 192.168.0.11 webserv
9 192.168.0.12 test
10 192.168.0.5 solaris10 # Added by DHCP
~
~
~
:6,9w >> /tmp/newfile
|
The vi editor is an extremely powerful tool, and this article provides you with a number of tips and tricks that will hopefully make your file editing more efficient. Remember, there's always more to vi that meets the eye. Happy editing!
Learn
-
UNIX tips
and tricks for a new user, Part 2: The vi text editor (Tim McIntire, developerWorks,
November 2006): Take this tutorial on the basic use of the vi editor.
-
vi intro - the
cheat sheet method (Daniel Robbins, developerWorks, November 2006): Discover
an accelerated "cheat sheet" for learning vi.
-
Learn Linux,
101: File editing with vi (Ian Shields, developerWorks, February 2010): Learn
how to use the vi editor.
-
AIX and UNIX developerWorks
zone: The AIX and UNIX zone provides a wealth of information relating to
all aspects of AIX systems administration and expanding your UNIX skills.
-
New to AIX and UNIX?
Visit the New to AIX and UNIX page to learn more.
-
Technology
bookstore: Browse the technology bookstore for books on this and other
technical topics.
Discuss
- Follow developerWorks on Twitter.
- Get involved in the My developerWorks community.
-
Participate in the AIX and UNIX® forums:
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- Virtualization Forum
- More AIX and UNIX Forums

Martin Wicks is a freelance UNIX consultant living and working in London, England. He has been working on UNIX systems for more than 15 years and for many years before that on IBM mainframes. He is a major film buff who enjoys snowboarding and mountain biking. You can reach Martin at wicksy@wicksy.com.



