The original vi
is a visual extension of an editor called ex
, itself an
evolution of the editors em and ed. The single-keystroke commands used in the
visual mode of the ex
editor were mappings to something that could be done
with the command mode of ex
. It’s therefore not quite right to say that vi
evolved from ex
; they’re the same program, differing only by invocation name
and default mode.
Vim follows the same lineage, and so for most of the basic functions you can do
in visual mode there exist analogues in the ex
command language, sometimes
enabling you to work with text in a more precisely defined way that can be
difficult using visual mode.
There are certain standard ex
commands that any Vim user will know, to edit
a file, save a file, quit, and to perform substitutions. But the actual command
set is vast, and there are a few tips using the ex
command set that turn out
to be very useful, particularly where filtering and transforming text is
involved.
Using ranges intelligently
Most of the familiar linewise commands in Vim operate on ranges of lines. Such an operation familiar to most Vim users will be the global substitution:
:% s/text/replacement/
The %
is shorthand for the entire file. By default, if you leave the %
out,
the substitute
operation operates on the current line:
:s/text/replacement/
To make this explicit, you could define the range with .
, which is a
shorthand for the current line:
:. s/text/replacement/
You can use line numbers to define on which line you would like the replacement to occur:
:20 s/text/replacement/
This also allows comma-separated definitions, defining the start and end of a range, which can be absolute, as with the following that makes substitutions only between lines 20 and 30:
:20,30 s/text/replacement/
Or relative to the current line, where the following makes substitutions from two lines above to two lines below the current line:
:-2,+2 s/text/replacement/
It’s also worth noting that the last line in the file can be referred to with
$
:
:20,$ s/text/replacement/
Finally, if you have any marks defined in your text, you can refer to them in
ranges by prefixing them with apostrophes. This will make substitutions from
the line marked with a
to the one marked b
:
:'a,'b s/text/replacement/
This also works with Vim’s automatic marks, such as the ones created for you
when you select some text in visual select mode. When you have some text
selected and you press :
to start a command, you might notice that Vim
automatically inserts the range definition for you, as below:
:'<,'> s/text/replacement/
Other linewise operations
Substitution is far from the only linewise operation available in ex
mode.
You can use d
to delete a range of lines:
:20,30 d
You can use y
to yank them into the default register for pasting later:
:20,30 y
You can use m
to move them to a specified line, and t
to copy them:
:20,30 m 40
:20,30 t 40
And finally, you can simply print all matching lines with p
:
:20,30 p
Text filters with g
and v
The g
and v
commands can be used to define ranges based on the results of a
regular expression search. Say you wanted to move all lines matching the
regular expression /vim/
to the top of the file. This is easily done with:
:g/vim/ m 0
Conversely, you can retrieve a range of lines that don’t match a regular
expression with v
:
:v/vim/ m 0
These become especially useful because you can combine searched ranges with
fixed ones, to only search a specified range of lines. In this example, only
lines from 10 to 20 matching the regular expression /vim/
will be moved:
:10,20 g/vim/ m 0
Normal-mode operations
As a final tip, if you define a range of lines, you can also use the normal
command to run a series of normal-mode keystroke commands on them. For example,
if you wanted to add a semicolon to every line matching /vim/
:
:g/vim/ norm A;
You can even extend this to run a macro held in a register over an appropriate
range of lines, which I think is one of the most elegant examples of composing
ex
tools in clever ways:
:g/vim/ norm @a