Grokking vi with ed

This document is to aid a new vi user into operating ex mode. This tutor is meant to further one's ability after they understand basic vi mode operations. If your an absolute beginner and have vim installed you can run the command “vimtutor” at your terminal. This document is meant to be read after the user is comfortable with the visual layer of vi.

Bill Joy’s vi was initially a five mode operational terminal editor. The current implementations only have four modes whereas the original fifth mode known as “open” mode was the same as the visual mode meant for terminals that had no screen cursor (i.e. paper based hardcopy terminals).

Both nvi and vim have the four modes of operation which are the visual presentation layer we know as vi, text input mode; accessible from the vi layer, the ex mode for executing commands as well as an input mode accessible from ex.

Though most users consider ex a mode of vi; the presentation layer is what they see when they first start the editor. Interestingly enough it’s the opposite. The vi layer is actually a mode built on top of ex; therefore is “visual on ex”.

The ex editor is based on source derived from ed, the venerable UNIX line editor. The tutorial uses syntax from ed to help new users understand how to use ex. Information on how to get into ex from vi mode is at the end of the tutorial.

From the command line to enter ed is is as simple as this syntax:

% ed -p '(ed)~> '

This will give it a nice user friendly prompt.

Append

First we will add some text to the buffer to work with. This is as simple as using the append command (a) which will put the editor into text input mode. To return to the command mode type single dot (.) at the beginning of the line followed immediately by a carriage return as so:

Code:
(ed)~> [B]a[/B]
The ed utility is a line-oriented text editor
Vi is a a screen oriented text editor
Vim  is a text editor that is upwards compatible to Vi
[B].[/B]
(ed)~>

Addressing

To address a line one could simply type the line number. for example to see the second line:

Code:
(ed)~> [B]2
[/B]Vi is a a screen oriented text editor

For adding text after a line address one would use the address combined with an append ‘a’ command as so:

Code:
(ed)~> [B]2a[/B]
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi
.

Print

To view the change one could also use a range for addressing with the command (p) to print the text in that range. Address ranges are delimited by the comma.
Code:
(ed)~> [B]2,4p[/B]
Vi is a a screen oriented text editor
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi
Vim  is a text editor that is upwards compatible to Vi

This can be read as follows: print from line 2 to line 4.

Insert

To enter text before a line one can insert text with the insert (i) command which in this case is the analog to ‘a’

Code:
(ed)~> [B]2i[/B]
The line editor ex, short for EXtended, is a fork of source derived from ed
.

To view the entire buffer, which contains could be titled “The Evolution of Unix Text Utilities”, one might consider the ‘1,5p’. Though this method will work the editor can address the variable last line with the currency symbol ($) thus can be written as 1,$p. Shorthand for printing the first line to the end is the percent symbol (%) which was further shortened to simply comma (,) for making it accessible for touch typists. Therefore all of these constructs will provide the same results:

Code:
(ed)~> [B]1,$p[/B]
(ed)~> [B]%p[/B]
(ed)~> [B],p[/B]

In ex the print (p) command is optional as it’s as it’s implied. Therefore the first two examples could be constructed as :1,$ and :% in ex. Finally the ed construct ‘,p’ is not interpreted in ex. For touch typists looking for a solution which would not require using shift key I have found that :1, works well.

The dot (.) will print the current line. Most commands leave the current line at the last which was affected. Here is an example usage of (.):

Code:
(ed)~> [B]3[/B]
Vi is a a screen oriented text editor
(ed)~> [B].[/B]
Vi is a a screen oriented text editor
(ed)~> [B]2[/B]
The line editor ex, short for EXtended, is a fork of source derived from ed
(ed)~> [B].,3p[/B]
The line editor ex, short for EXtended, is a fork of source derived from ed
Vi is a a screen oriented text editor
(ed)~> [B].,$[/B]
Vim  is a text editor that is upwards compatible to Vi

To address before the first line the user can use address 0 where it makes sense. For example 0a would be the equivalent to 1i in ed. Though 0i doesn’t work in ed; it is interpreted in ex. The simple fact that ex knows “what the user meant” shows where Joy wanted a more user friendly version of ed when creating ex.

Delete

Here is example usage which also shows how one would use delete (d) to remove one or more lines and finally to change (c) a line :

Code:
(ed)~> [B]0i[/B]
?
(ed)~> [B]0a[/B]
top
.
(ed)~> [B]1,2p[/B]
top
The ed utility is a line-oriented text editor
(ed)~> [B]1c[/B]
This is the top
of the file
.
(ed)~> [B]1,4p[/B]
This is the top
of the file
The ed utility is a line-oriented text editor
The line editor ex, short for EXtended, is a fork of source derived from ed
(ed)~> [B]1,2d[/B]
(ed)~> [B]%p[/B]

The last statement you’ll see that the file is intact. If a mistake was made the user could undo (u) the last operation with the ‘u’ command.

Join

The final command to take only a range is to join (j) two lines together. The operation will combine two or more lines into one. An example join line 4 to the end of line is (3,4j) or line 3 to the END of the document to line 2 would be (2,$j).

List

The join (j) command would be best to used in conjunct with the list (l) command which prints the text with a currency symbol ($) at the end of each line where a carriage return has taken place. The command (%l) will show where all the carriage returns are in the buffer.

Change

The change (c) command can take a range address as well such as (2,4c or .,$c). The behavior is the same. If the range is of three lines those three lines will be replaced If less than three lines are entered through input mode the rest of the text is truncated to the last entered line. It’s essentially a combination of delete the addressed line (1d) and insert at the addressed line (1i).

Input commands boil down to a (append), i (insert) or c (change). These are the only commands which will move the editor from command mode to input mode.

Address Numbering

To view the number of lines in in the buffer the (=) symbol will provide the integer. In combination with the current line number would be to combine the two as so ‘.=’ . Numbers can be printed at the beginning of the line with the number (n) command. Here is an example:
Code:
(ed)~> [B]4[/B]
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi
(ed)~> [B].[/B]
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi
(ed)~>[B] .=[/B]
4
(ed)~> [B]1[/B]
The ed utility is a line-oriented text editor
(ed)~> [B].[/B]
The ed utility is a line-oriented text editor
(ed)~> [B].=[/B]
1
(ed)~> [B]=[/B]
5

Commands may require zero, one, or two addresses. If no address is given the default address (.) is implied.

Move and Transfer: cut, copy and paste

The last two line based operations are similar to the gui paradigm of cut, copy, and paste. In vi mode to copy a line one would “yank” the text and to paste one would “put” the yanked text a line below where the cursor was placed. In ed and ex the operations are a bit simpler. The awkwardly named transfer (t) command is a copy then paste operation which syntax would look like (4,5t2) which copies lines 3 through 4; then pastes them to line 2. The move (m) command has the same structure; its operation is effectively the same as the cut and paste metaphor today. A simple move example would be (3,$m0) which is cut lines 3 through END and paste the lines to the beginning of the file.
 
Context Search

Though the use of addresses is one way to navigate and operate on the buffer; context searches may be used where a line number is not known. The operation is best suited for larger buffers. To do a forward search the (/) symbol is used and to do a reverse search (?) symbol is used. Here are examples of context searching:
Code:
(ed)~> [B]/ed[/B]
The ed utility is a line-oriented text editor
(ed)~> [B]/Vi[/B]
Vi is a a screen oriented text editor
(ed)~> [B]?ex[/B]
The line editor ex, short for EXtended, is a fork of source derived from ed
(ed)~> [B]/EX[/B]
The line editor ex, short for EXtended, is a fork of source derived from ed
(ed)~> [B]/screen/,/BSD/p[/B]
Vi is a a screen oriented text editor
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi

As one might observe the concept of context searching parses the whole line for a match. The pattern after (/) or (?) is a regular expression literal. To repeat the search incrementally the syntax would be ‘//’ to move to the next match and ‘??’ to move to the previous. The last example shows a context search to fulfill the same role as range addresses where ‘/screen/,/BSD/p’ is the same as ‘3,4p’.

Though this is not a tutorial for regular expressions it is an essential part of the UNIX system and these editors. The next logical step to have more granular control over your text manipulation; only after running through this tutorial, is to become familiar with regular expressions.

A more experienced user will also note that these work the same way they do on the system pager commands (more) and (less). The systems manual (man) use environment defaulted pager to view and study commands. Though originally intended to use shared resources as the original time sharing systems were limited; there is the by-product that the user can learn one paradigm to be used in many system utilities.

Vi users can access context searches without ever going into ex by typing either / or ? from visual mode which is synonymous with the aforementioned system utilities. To step through to the next match is forward (n) and reverse (shift-n).

Global

Global searching can be done by prepending the context search with the global (g) command. The common usage of global context searching within the buffer was so popular it would eventually be duplicated into the utility known as grep (global regular expression print). The analog to (g) is (v) which selects lines which do not match the expression. Here is example usage:

Code:
(ed)~> [B]g/Vi/p[/B]
Vi is a a screen oriented text editor
Vim  is a text editor that is upwards compatible to Vi
(ed)~> [B]g/re/p[/B]
Vi is a a screen oriented text editor
Bostic’s nvi is a bug-for-bug compatible replacement of 4BSD vi
(ed)~> [B]v/re/p[/B]
The ed utility is a line-oriented text editor
The line editor ex, short for EXtended, is a fork of source derived from ed
Vim  is a text editor that is upwards compatible to Vi

Shell

External commands can be executed directly inside the editor where the commands would be prepended by the bang (!) symbol. One might observe that this predates the hash-bang (#!) shell interpreter directive. Entering the shell without closing the editor is as simple as (!sh). The user then can do what ever they need on the shell, even open up a new editing session, and when they are finished they can quit the shell <ctrl-d> and it will return to ed. Alternate shells can be used as well when the system sh is undesired; such as (!zsh) for the z shell.

Read

External commands can be read back into a specific position of the buffer as well. This can be provided from the read (r) command with a positional parameter. For example if the user wanted to put the output of the unix date command at the head of the document the syntax would be (0r !date).

File Association

To place the buffer into a file the write (w) command alone will write to a file if it’s specified. To see the file associated the file (f) command alone will reveal it’s name. If there is no association both (f) and (w) commands will take a full path with the name of the file. The default path is the location of the directory in which you launched the editor. It is useful to know that the write (w) command can take an address to only write out specific portions of the buffer.

Code:
(ed)~> [B]f[/B]
?
(ed)~> [B]f /tmp/junk[/B]
/tmp/junk
(ed)~> [B]f[/B]
/tmp/junk
(ed)~> [B]w[/B]
277
(ed)~> [B]!tr 'A-Za-z' 'N-ZA-Mn-za-m' < %[/B]
Gur rq hgvyvgl vf n yvar-bevragrq grkg rqvgbe
Gur yvar rqvgbe rk, fubeg sbe RKgraqrq, vf sbex bs fbhepr qrevirq sebz rq
Iv vf n n fperra bevragrq grkg rqvgbe
Obfgvp'f aiv vf n oht-sbe-oht pbzcngvoyr ercynprzrag bs 4OFQ iv
Ivz  vf n grkg rqvgbe gung vf hcjneqf pbzcngvoyr gb Iv
!

The last line shows how an external command could be used. In this case tr is used as rot13 also known as the caesar cipher. The percent (%) in this case represents the file and will expand to /tmp/junk when the command is executed.

Though this is not a tutorial on simple encryption it is worth exploring in vi. To leave the editor the command is quit (q). If the contents have not been saved it is best to do so so we will finish this tutorial in vim. If you see a (?) after giving the (q) command it means that you have not saved the buffer much in the same why you would have to use the (q!) in vi.

Once in vi you can access ex from pressing the colon (:) which returns to the visual mode right after execution of a single command or pressing the escape key. An alternate way enter ex is to press <shift-q> or (Q) which will allow ex to work as a pure line editor much like ed. The command to switch back to vi from ex is either :vi or :visual.

Finally from the shell prompt the command vi will begin in visual mode and vi -e will begin in command mode just the same as the ex command will enter command mode respectively as well as ex -v will enter visual mode.

% vim -e /tmp/junk
Code:
"/tmp/junk" 5L, 277C
Entering Ex mode.  Type "visual" to go to Normal mode.
:[B]vi[/B]

To alter text within the document via external command the user can prefix the bang command with an address or context search. Here are some examples with using our rot13 statement:

Code:
:[B]/EX/,/BSD/!tr 'A-Za-z' 'N-ZA-Mn-za-m'[/B]
:$[B]!tr 'A-Za-z' 'N-ZA-Mn-za-m'[/B]
:[B]2,$!tr 'A-Za-z' 'N-ZA-Mn-za-m'[/B]
:[B]%!tr 'A-Za-z' 'N-ZA-Mn-za-m'[/B]

If the last command is executed a second time the text will decrypt to the original form.

Substitute

The substitute command is one of the most useful commands to be used within these editor. The commands primary function is to search and replace. The main construct is (s/pattern/replace). Within ex it works one the first pattern it finds on the line which it’s executed. If the there exists a repeated pattern the global (g) can be postfixed to the substitute statement alter further instances in that line.

Addressing can be used to alter specific lines or the whole file. The special ampersand character (&) can be used within the ‘replace’ portion of the construct as shorthand to reuse the characters in the pattern without retyping them. An example of (&) usage would be :)s/re/&place) which will match the first instance of the letters ‘r’ followed by ‘e’ and change them to ‘replace’.

Code:
:[B]s/ed/QED[/B]
The QED utility is a line-oriented text editor

Simple replace with literal context.
Code:
:[B]/screen/ s/$/; created by Bill Joy/[/B]
Vi is a screen oriented text editor; created by Bill Joy

The currency symbol in regular expressions represents the end of line therefore in the context above appends at the end.
Code:
:[B]%s/^Bostic/Keith &/g[/B]
Keith Bostic's nvi is a bug-for-bug compatible replacement of 4BSD vi
The circumflex (^); or carrot is the analog of $ and represents the beginning of line. When alone it can be used to insert text at the beginning of the line.

Code:
:[B]$s/Vi\>/Joy's &/[/B]
Vim  is a text editor that is upwards compatible to Joy's Vi

The backslash greater than \> represents the end of a word. The backslash less than is the analog and represents the beginning of the word \<. These are useful for having more granular control over your matching. If it was not used in the previous example it would have matched word ‘Vim’ at the beginning of the line which was not was intended.
 
Pipe

To remove content within the buffer the last set of forward slashes should have no white space. The pipe (|) represents a delimitation of commands and allows multiple commands to coexist on the same line.
Code:
:[B]%s/4//g[/B]
Keith Bostic's nvi is a bug-for-bug compatible replacement of BSD vi
:[B]%s/\<BSD/Free& UNIX/[/B]
Keith Bostic's nvi is a bug-for-bug compatible replacement of FreeBSD UNIX vi
:[B]s/of/for/ | s/\<vi\>//[/B]
Keith Bostic's nvi is a bug-for-bug compatible replacement for FreeBSD UNIX

Addressing Arithmetic


Both (+) and (-) symbols are considered relative positional parameters for operations that need to be done a line before or after the absolute line address.
Code:
:[B]%#[/B]
 1 The QED utility is a line-oriented text editor
 2 The line editor ex, short for EXtended, is a fork of source derived from ed
 3 Vi is a a screen oriented text editor; created by Bill Joy
 4 Keith Bostic's nvi is a bug-for-bug compatible replacement for FreeBSD
 5 Vim  is a text editor that is upwards compatible to Joy's Vi
:[B]4-#[/B]
 3 Vi is a a screen oriented text editor; created by Bill Joy
:[B]4-2#[/B]
 2 The line editor ex, short for EXtended, is a fork of source derived from ed
:[B]2+3#[/B]
 5 Vim  is a text editor that is upwards compatible to Joy's Vi
:[B]/fork/+2#[/B]
 4 Keith Bostic's nvi is a bug-for-bug compatible replacement for FreeBSD

Regular Expressions

In conclusion new users will want to explore regular expressions for further power usage.

Many utilities derived from ed beyond the visual editor such as grep, sed and the awk programming language which was initially created for users to script custom filters. The Perl programming language was conceived as an alternative to the “Does one thing and does it well” UNIX philosophy. The Ruby programming language was influenced directly by Perl; as well as Python, Smalltalk and Lisp. Ruby provides a native regular expression class to instantiate regex objects.

Though Ruby and Perl have regular expressions built directly into the language, other languages such as Python or C++ have access to them via language extension or library.

A more interesting note is that the shell provided filename expansion via glob; shortened from global. Within the shell the only a small subset could be used. Modern interactive shells, such as the Z Shell (zsh), provide an option to extend the set to proper regular expression syntax.

Vim users may want to look into an extension called magic and very magic which enables various methods for dealing with escaping regular expression syntax with various regex implementations.

Happy Hacking.
 
Final Thoughts:

This tutorial was written in response to a common diatribe among new users I have spoken with on irc and various local user groups on the vi learning curve.

The muscle memory to set in for visual mode could easily take a user several months to get used to. To make matters worse the shell defaults to emacs binding for shell line editing which effectively extends the learning curve.

Once the transition is made; these "bindings" will become second nature providing the user a fluid experience at the terminal as well as useful skills for the rest of their lives.

It is the author's hope that the information herein will alleviate the new user's frustrations with grokking vi.

~

History:
  • 1956 Stephen Cole Kleene, a student of Alonzo Church (lambda calculus), describes regular sets; mathmatical notation to describe automata and formal language theory. What we refer today as regular expressions.
  • 1962/63 TECO (paper) Tape Editor and COrrector is the oldest incarnation of the editor.
  • December 1967 QED 'quick' editor written by Butler Lampson and Peter Deutsch for the Berkeley time-sharing system on the SDS 940 *
  • Ken Thompson implemented QED in IBM 7090 assembly language for MIT CTSS (Compatible Time-Sharing System) introducing NDFA regular expressions to the editor.
  • Thompson once again reimplemented QED, this time in BCPL, for the Multics project (Multiplexed Information and Computing Service).
  • 1969 Thompson creates ed in assembly for UNICS (UNiplexed Information and Computing Service) after he returns to Bell Laboratories. Ritchie begins working on what would become the C programming language.
  • 1972-1973 Dennis Ritchie's C programming language is implemented; ed is written in C; the kernel is rewritten and the system can compile itself. Kernighan suggests a new name; the system is renamed UNIX.
  • 1975-77 Bill Joy starts hacking em, "editor for mortals", which is George Coulouris' fork of Thompson's ed. Joy versioned by letter from em to en to ex.
  • 1977 Joy distributes 1BSD with ex and a pascal system.
  • 1978 2BSD which implemented vi (the visual version of ex) and the C shell.
  • 1987 Stevie (ST editor for VI enthusiasts) a vi clone by Tim Thompson is released.
  • 1988 Bram Moolenaar begins to work on vim on his Amiga computer with stevie as the source.
  • 1990 Steve Kirkendall posted elvis (a vi clone) to USENET. Keith Bostic proposes removal of non-AT&T code Within eighteen months, all the AT&T utilities had been replaced. Bostic used the source from elvis to create a bug-for-bug comparable clone nvi (new vi).
  • 1991 vim (Vi IMitation) is released to the public
  • 1993 Moolenaar changes the acronym to "Vi IMproved" as vim surpassed the original vi feature set.
Descendants:
Utilities and programming languages which where are where influenced from ed:

ed (1971) --> grep (1973) --> sed (1974) --> awk (1977) --> perl (1987) --> ruby (1993)

Historical MAN pages:

Bill Joy's ex/vi man pages:
ex(1)
vi(1)

Original ed source:
http://www.tuhs.org/Archive/PDP-11/Trees/V6/usr/source/s1/ed.c

The ADM-3A keyboard layout Joy used as a template for vi:
https://upload.wikimedia.org/wikipedia/commons/a/a0/KB_Terminal_ADM3A.svg

UNIX 1st edition:
ed(1)
UNIX 6th edition:
ed(1)
UNIX 8th edition:
ed(1)
vi(1)
Plan9:
ed(1)
Sun Microsystems man pages:
ed(1) << this is the most complete.
ed(1)
ex(1)
vi(1)

Papers:
An Introduction to Display Editing with Vi
Ex Reference Manual

QED manual (in html) authored by Dennis Ritchie and Ken Thompson.
http://cm.bell-labs.com/who/dmr/qedman.html
There is a nice section explaining regular expressions. Please note DMR's note at the top dating it at June 22, 1970.
This is the original document scan:
http://cm.bell-labs.com/cm/cs/who/dmr/qedman.pdf

BSD ed additions can be seen in source /usr/src/bin/ed
1) BSD commands have been implemented wherever they do not conflict with
the POSIX standard. The BSD-ism's included are:
i) `s' (i.e., s[n][rgp]*) to repeat a previous substitution,
ii) `W' for appending text to an existing file,
iii) `wq' for exiting after a write,
iv) `z' for scrolling through the buffer, and
v) BSD line addressing syntax (i.e., `^' and `%') is recognized.

There is a tutorial in the source for nvi /usr/src/contrib/nvi which can be run with:
% /usr/src/contrib/nvi/docs/tutorial/vi.tut.csh beginner
or
% /usr/src/contrib/nvi/docs/tutorial/vi.tut.csh advanced
 
Back
Top