Using more of ex

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