---
title: 'Terminal Text Editors'
source: 'https://academia.sh/en/courses/introduction-to-linux/terminal-text-editors'
course: 'Introduction to Linux'
language: en
updated: '2026-08-17T18:09:57+00:00'
license: 'CC BY-SA 4.0'
---

# Terminal Text Editors

The design line from line editor to screen editor, comparing modal and modeless editors, basic editing commands, and declaring an editor choice through an environment variable.

Files throughout the course were created with `printf` and redirection. That works for
one-line files; it is not enough for changing a line in the middle of a script or adding two
lines to a configuration file.

On a server with no graphical interface — the case for most remote sessions — editing is done
in the terminal. This lesson covers the two design families of terminal editors and the choice
between them.

## The Line Editor

Terminal editors' design comes from the era when printing terminals were used. There was no
screen back then; output was printed on paper, and moving a cursor was not a thing. Editing
was done with commands over line numbers.

This design's representative, `ed`, is still defined in POSIX and still works. A complete
session to add a line to the project script:

```
$ ed scripts/summary.sh
142
$
echo "raw measurement file: $(ls -1 "$HOME/project/data/raw" | wc -l)"
a
echo "current measurement: $(readlink "$HOME/project/data/current.csv")"
.
%p
#!/bin/sh
# Reports the count of measurement files in project/data/raw
echo "raw measurement file: $(ls -1 "$HOME/project/data/raw" | wc -l)"
echo "current measurement: $(readlink "$HOME/project/data/current.csv")"
w
215
q
```

The session should be read line by line. The `142` printed at open is the file's byte count.
The `$` command prints the last line. `a` switches to append mode; the following lines are
added to the file, and a lone period ends append mode. `%p` prints the entire file. `w` writes
and reports the new byte count, `q` quits.

`ed` shows no prompt and prints only a question mark on error. This is inconvenient for
everyday use, but matters for two reasons. First, its command language has been inherited in
full by later editors. Second, `ed` can be driven from scripts through redirection, and this
is sometimes the only option in rescue environments.

## The Modal Screen Editor

Once screen terminals became widespread, a **visual mode** was added on top of the line
editor: part of the file is shown on screen, and the cursor moves over it. This design was
standardized in POSIX under the name `vi` and is expected to be present on every
standard-conforming system.

The editor's distinguishing feature is its **modes**. The same key does different things
depending on the current mode:

| Mode | Function | How to enter |
|---|---|---|
| Normal | Navigation and editing commands | `Esc` |
| Insert | Typed characters go into the text | `i`, `a`, `o` |
| Command line | Line editor commands | `:` |

The design's rationale is that keys become a **language**. Because letter keys do not enter
characters in normal mode, all of them can be used as commands; commands themselves are built
by combining an action with a motion. `d` is the delete action, `w` is a word-forward motion;
`dw` deletes a word. `3dw` deletes three words. Every learned motion can combine with every
learned action.

The approach it is contrasted with is binding commands to modifier-key combinations. In that
approach the number of commands is limited by the number of combinations, and combinations
cannot be composed.

The modal design's second gain is that it uses only basic characters: it works on terminals
that do not send arrow keys or modifier combinations. This is a practical advantage for remote
sessions and rescue consoles.

Its cost is that a command typed in insert mode gets mixed into the text. Mode confusion is
the problem new users run into most, and its fix is fixed: when unsure, press `Esc` and return
to normal mode.

## The Smallest Survival Set

The commands needed to open, change, and save a file are few:

| Command | Function |
|---|---|
| `i` | Enters insert mode before the cursor |
| `a` | Enters insert mode after the cursor |
| `o` | Opens a new line below and enters insert mode |
| `Esc` | Returns to normal mode |
| `h` `j` `k` `l` | Left, down, up, right |
| `0` / `$` | Start of line / end of line |
| `gg` / `G` | Start of file / end of file |
| `x` | Deletes the character under the cursor |
| `dd` | Deletes the current line |
| `u` | Undoes the last change |
| `/pattern` | Search forward; `n` for next match |
| `:w` | Saves |
| `:q` | Quits |
| `:q!` | Quits, discarding changes |
| `:wq` | Saves and quits |

Commands beginning with a colon in the last four rows are the line editor's commands. The
inheritance shows here: `:w` and `:q` are the same commands as `w` and `q` in an `ed` session.

The same command language can also be run directly; the editor's line mode can be driven from
scripts:

```
$ printf '%s/file/count/\nwq\n' | ex -s /tmp/edit.sh
$ cat /tmp/edit.sh
#!/bin/sh
# Reports the count of measurement files in project/data/raw
echo "raw measurement count: $(ls -1 "$HOME/project/data/raw" | wc -l)"
echo "current measurement: $(readlink "$HOME/project/data/current.csv")"
```

The `%s/old/new/` command makes the substitution on every line; `wq` saves and quits. Typing a
colon in the screen editor and giving the same command produces the same result. A
screen-based session cannot be shown as text, but the command language can, and that is what
is shown here.

## Modeless Editors

The second design family uses no modes: typed characters go straight into the text, commands
are given with control-key combinations, and the available commands are listed continuously
at the bottom of the screen.

The comparison runs along two axes:

| Criterion | Modal | Modeless |
|---|---|---|
| Learning threshold | High; the mode concept must be learned | Low; commands are written on screen |
| Command composition | Action and motion combine | One command per combination |
| Guaranteed presence | Defined in POSIX, expected on every system | Separate package, may not be installed |
| Limited terminal | Works with basic characters | Needs control combinations |

The third row is decisive in practice. A modeless editor may not be present on a bare system
or in a rescue environment:

```
$ command -v vi ed nano
/usr/bin/vi
/usr/bin/ed
/usr/bin/nano
```

All three exist on this system; but only the first two can be assumed present. For this
reason, the modal editor's survival set should be learned regardless of which editor is
preferred.

## Declaring an Editor Preference

Many programs launch an editor when editing is needed: scheduled-task definitions, version
control tools' message screens, privileged file-editing tools. Which editor opens is read from
environment variables.

```
$ echo "EDITOR=${EDITOR:-undefined}"
EDITOR=undefined
$ EDITOR=vi
$ export EDITOR
$ echo "EDITOR=$EDITOR"
EDITOR=vi
```

An assignment made without `export` becomes only the shell's own variable and would not be
passed to programs it runs; the environment distinction from the command path lesson applies
directly here. For the setting to persist, it is written to the same place as the `PATH`
change — the configuration file read at login.

Two variables are used: `VISUAL` for a full-screen editor, `EDITOR` for line-based
environments. If both are defined, most programs prefer `VISUAL`; if only one will be defined,
`EDITOR` is enough.

## Summary

- Terminal editors' command language is inherited from the line editor designed for screenless
  terminals, and it is still visible in commands beginning with `:`.
- In the modal editor, letter keys can be used as commands, so action and motion combine into
  a command language.
- The command set needed to open, change, and save a file is small, and pressing `Esc` returns
  to normal mode when unsure.
- Modeless editors have a low learning threshold but cannot be assumed present on every
  system.
- Editor preference is declared through the `VISUAL` and `EDITOR` environment variables and is
  not passed to run programs unless `export`ed.

## Course Wrap-Up

The course progressed over a single directory tree. The tree was empty when set up; by the
close it carries every operation performed on it:

```
$ scripts/summary.sh
raw measurement file: 4
current measurement: raw/measurement-03.csv
```

The whole course stands behind these two lines. For the script to run, it had to be on the
search list and have its execute bit on. The files it counts were created, copied, and moved;
the directory they were counted in was found through path resolution. The current measurement
it reports is a symbolic link's target. The whole tree was archived, compressed, synced to a
remote machine; opened to a group and its shared directory protected with special permission
bits.

The course's takeaways sum up in retrospect as follows:

- **Navigation and file operations:** The hierarchy's logic, path resolution, creating,
  copying, moving, deleting, links, archiving, and transfer.
- **Permissions and ownership:** Identity's numeric representation, the nine permission bits
  and octal notation, changing ownership, privilege escalation, and the three special bits.
- **Package management:** A package's structure, dependency resolution, operation classes, and
  the repository's chain of trust.

Alongside commands, a set of habits was built through the course, and these outlive the
commands themselves: seeing a destructive command's expansion before running it, listing an
archive before opening it, trying a sync with a dry run first, verifying a transfer against
its checksum, and taking a privilege in the narrowest scope possible.

The next course covers the layer this course deliberately left out: chaining commands
together. The Shell Programming course builds input and output redirection, pipelines,
variables, conditionals, and loops; commands run one at a time in this course turn there into
scripts that can be run again. The word-splitting and expansion rules introduced in the shell
lesson will form the foundation of that course's grammar.
