jxself.org

A Deep Dive into the ed Text Editor

Sun, 30 Nov 2025

There's a long-running joke, a shibboleth tossed at new users, that "ed is the standard editor". This is often said with a wry smile, as ed is notoriously user-unfriendly. Its default state is a blank line, it offers no prompt, and its only error message is a single, cryptic ?.

But the secret, and the reason the joke has such staying power, is that it's fundamentally true. For early Unix, ed was the standard text editor. To this day, it remains a required component of the POSIX standard, meaning it's present on virtually every Unix-like system on earth.

In an age of "over-engineered IDEs" and "kitchen sink" configurations, ed represents a different path. Its brutal simplicity isn't a flaw; it's a design philosophy. This deep dive will explore the power and elegance of ed.

For the uninitiated, ed's a line-oriented and modal text editor. This means you don't see or edit a full screen of text. You operate, by default, on one line at a time using a precise set of commands. It's this command-driven nature that unlocks its true potential.

To understand ed, one must be transported to August 1969 at AT&T Bell Labs. Ken Thompson, a co-author of Unix, was working on a PDP-7 and developed the three primordial elements of this new OS: the assembler, the editor, and the shell. That original editor was ed.

The "user interface" for this new system wasn't a glass video monitor. Instead it was a Teletype Model 33, a slow, noisy mechanical printer equipped with a keyboard. The limitations of this machine shaped ed's design. The teletype printed only 10 to 15 characters per second - so slow that even the simplest confirmation message would waste time and paper. It also printed output line by line onto a physical roll of paper, making every line permanent once produced.

These constraints led to design choices that can feel cryptic today but were ingenious optimizations at the time. Ed's silent because each unnecessary character was costly; no prompt or default feedback meant the machine avoided wasting both seconds and paper. Scrolling was impossible, since the Teletype had no display - only a one-directional roll of paper. To see the past you only need to look at the physical piece of paper. Editing had to occur line by line, operating on an invisible copy of the file in memory. Even the infamous "?" error was an act of efficiency: one character that communicated failure in the most compact way possible. The later GNU ed option that prints verbose errors is a luxury never imagined in its original environment.

Ed's design isn't user-hostile; it's eesource-friendly, an elegant tool perfectly tailored to its constraints.

Its technical lineage is equally foundational. Ed was inspired by QED (Quick Editor) from UC Berkeley, Thompson's alma mater. Thompson's adaptation of QED - and its successor ed - were notable for introducing regular expressions to Unix text editing. Dennis Ritchie refined this capability into what became the definitive ed, and from it emerged the DNA of Unix text-processing philosophy. Ed's the direct ancestor of tools like grep and sed, and the concept of text streams as a universal interface in Unix begins here.

An Interactive ed Session

Let's face the void. When you launch the editor by typing ed at your prompt, you are greeted with... nothing. The editor's running, silently waiting in command mode.

Before doing anything else, modern GNU ed provides two "magic" commands that make it usable for beginners.

  1. Type P (uppercase) and press Enter. This toggles a prompt, so you know ed is in command mode. The default prompt is an asterisk (*).
  2. Type H (uppercase) and press Enter. This toggles verbose help for errors. Now, the infamous ? will be replaced with a helpful message, such as "Unknown command."

Let's try a complete "Hello, World" workflow.

  1. Enter Input Mode: We start in command mode. To add text, we must enter input mode. Type a (for "append") and press Enter.
  2. Add text: ed is now in input mode, ready to append text after the current line (which is line 0 in an empty file). Let's type our text: Hello, world.
  3. Return to Command Mode: To stop inputting, type a single period on a line by itself and press Enter. This is the most common point of confusion for new users.
  4. View the Buffer: The text isn't yet in a file; it's in a memory buffer. To see what's in the buffer, we use the p (print) command. A common shortcut is ,p (comma-p), which is shorthand for 1,\p - meaning "from line 1 to the last line (), print".
  5. Save the Buffer (Write): The w (write) command saves the buffer to a file. Let's write to hello.txt by entering: w hello.txt. ed helpfully responds with the number of bytes written to the file.
  6. Quit: The q (quit) command exits the editor.

The mental model is simple but rigid. ed has two modes.

  • Command Mode: The default, where you issue commands like a (append), i (insert before), c (change), s (substitute), w (write), and q (quit).
  • Input Mode: Entered via a, i, or c. In this mode, you can only type text. You cannot edit. You must return to command mode to perform any edits. This is a direct relic of the teletype, where you couldn't move a cursor up to fix a typo. You had to finish your line and then issue a new command to change it.

Unlocking the Power: From Lines to Programs

The true power of ed isn't in appending text, but in its sophisticated line addressing. Every command can be prefixed by an address (a line number, or range) to operate on.

  • . : The current line.
  • : The last line in the buffer.
  • n : A specific line number (e.g., 3p prints line 3).
  • n,m : A range of lines (e.g., 1,5p prints lines 1-5).
  • , or \% : A shortcut for the entire file (1,\).
  • /regexp/ : The first line after the current one that matches the regular expression. This is addressing by searching.

This addressing system turns three simple commands into a powerful toolkit.

1. s (Substitute)

This is the find-and-replace command. Its syntax is [address]s/regexp/replacement/[flags].

  • Example: 1,\s/foo/bar/g
  • Translation: "From line 1 to the last line (1,\), substitute (s) the regular expression foo with the text bar, and do it globally (g) on each line (i.e., replace all instances, not just the first)".
  • In the replacement string, & (ampersand) refers to the entire matched text.

2. g (Global)

This is the single most powerful command in ed. It's not just a command; it's a control structure. The syntax is [address]g/regexp/command(s).

  • Translation: "For every line in the given address range (defaulting to the whole file) that matches /regexp/, execute the following command(s) on that line".
  • This is a foreach loop. It's programming.
  • Example: g/DEBUG/d
  • Translation: "For every line in the file containing the text "DEBUG", execute the d (delete) command." This deletes all debug lines from a file.

3. v (Inverse Global)

This is the counterpart to g. The syntax is [address]v/regexp/command(s).

  • Translation: "For every line in the given address range that does NOT match /regexp/, execute the following command(s)". This is the equivalent of grep -v.
  • Example: v/FINAL/d
  • Translation: "Delete all lines except those containing "FINAL"."

These can be combined. A command like g/config_option/s/false/true/ translates to: "First, find (g) all lines containing config_option. Then, only on those lines, substitute (s) the first instance of false with true".

This g command is the key to all of Unix text processing. The ubiquitous grep utility isn't a random name. It's the literal ed command g/re/p. The command global/regular expression/print (find all lines matching a pattern and print them) was such a typical ed use case that Ken Thompson extracted it into a standalone program. ed isn't just an editor; it's the progenitor of the Unix toolbox.

The ed Command and Addressing Reference

Category Command Syntax Description
Shell H H Toggles verbose error messages (GNU ed).
P P Toggles command prompt (GNU ed).
q q Quits the editor. Q quits unconditionally.
Buffer w [range]w [file] Writes the (ranged) buffer to a file. W appends.
e e [file] Discards the current buffer and starts editing a new file.
r [addr]r [file] Reads a file and inserts its contents after the given address.
Addressing . . The current line.
The last line in the buffer.
, or % ,p or %p Address range for the entire file (1,\).
/re/ /[regexp]/ Addresses the next line matching the regular expression.
Editing a [addr]a Appends text after the addressed line.
i [addr]i Inserts text before the addressed line.
c [range]c Changes the lines in the range with new text.
d [range]d Deletes the lines in the range.
u u Undoes the last command.
Display p [range]p Prints the lines in the range.
n [range]n Prints lines, but with numbering.
l [range]l Prints lines, but "lists" non-printing characters.
Power s [range]s/re/rep/[g] Substitutes re with rep. g makes it global on the line.
g [range]g/re/cmd Globally executes cmd on all lines matching re.
v [range]v/re/cmd Inverse global. Executes cmd on lines not matching re.

ed's history's fascinating, but why learn ed when we have emacs, vi, nano, and more?

The answer is that ed isn't for interactive, day-to-day writing. Its modern role is as a powerful, silent, and reliable scripting tool.

When a shell script needs to modify a file, most people reach for sed -i (the "in-place" flag). This is, however, often the wrong choice.

  • sed is a stream editor. It's designed for one-pass transformations on data in a pipeline.
  • ed is a file editor. It's designed to load a file into a buffer, operate on it, and save it.

The sed -i flag (on GNU sed) is a hack. It doesn't edit "in-place." It works by creating a new temporary file and then replacing the original file with it. This operation is problematic: it breaks hard links, can fail if another process has the file open, and can create issues with file permissions.

ed performs a true in-place edit. It opens the file, reads it into its buffer, performs all operations in memory, and then, on a w command, writes the buffer's contents back into the original file. For scripts that need to robustly and atomically edit a configuration file, ed's the more correct and more reliable tool.

Furthermore, ed is its own REPL (Read-Eval-Print-Loop). Debugging a complex sed script's a nightmare of trial and error. With ed, you can interactively load a file, build your complex command (g/foo/?bar?s/baz/qux/g), test it with p, undo it with u, and perfect it. Once it's proven, you copy that command into your script.

ed can be "driven" from a shell script in two main ways:

Example 1: Using printf and a pipe

This script inserts a new line at the top of a config file.

# Add a new line at the beginning of a file
CONFIG_FILE="/etc/my.conf"
NEW_LINE="options=new_value"
# -s suppresses output
# 1i = Insert at line 1
# . = Exit input mode
# w = Write
# q = Quit
printf '%s\n' '1i' "NEW_LINE" '.' 'w' 'q' \
| ed -s "CONFIG_FILE"

Example 2: Using a Here-Document

This is more readable for complex edits, like changing a value.

# Find and replace a value in a config file
# This will change 'DEBUG=true' to 'DEBUG=false'
ed -s /etc/app.conf <<EOF
H
g/DEBUG=true/s//DEBUG=false/
w
q
EOF

The second modern use case is as your safety net.

The Scenario: Your machine fails to boot. It drops you into a single-user recovery mode. You discover the /usr partition (which might be on a failed disk or a failed network mount) isn't mounted.

The Problem: Where do vi, vim, nano, and emacs live? They all live in /usr/bin. They're gone.

The Solution: ed lives in /bin. It's tiny (often and has almost no dependencies. It will be there. ed is the only editor you can count on to fix your /etc/fstab or a broken init script when your system is truly broken.

The "I'll just use vi" argument's flawed. vi is the editor for healthy systems. ed is the editor for broken ones. Learning the ten basic commands - a, i, d, p, w, q, H, P, , and s - isn't a trivial pursuit; it's an emergency toolkit.

ed has quite the legacy. The entire lineage of modern terminal editors flows from it: From ed (Ken Thompson, 1969) to ex ("extended ed," Bill Joy, 1976) to vi (the "visual" mode for ex, Bill Joy, 1976) to vim ("Vi Improved," Bram Moolenaar, 1991).

This lineage holds one final, profound secret. If you're a vi or vim user, you are already an ed user. You don't know it. When you are in vim and type : (colon) to enter command-line mode, you are not simply entering a "command." You are dropping down into ex mode. And ex is, for all intents and purposes, a superset of ed.

Every "ex command" you run - :%s/foo/bar/g, g/re/d, :w, :q - isn't a vi command. It's an ex command, using the exact syntax, grammar, and philosophy of ed.

Learning ed isn't about mastering an "obsolete" editor. It's an archeological dig that reveals the living-fossil DNA inside the tools you use every day. It's about learning the root language of text editing.

ed's the purest expression of the Unix philosophy. It does one thing, it does it well, and it does it with a "brutal elegance" born of necessity. It teaches us that minimalism isn't about a lack of features; it's about the elegance of having just enough. In an era of digital excess, ed isn't just a tool. It's a history lesson and a design philosophy, waiting for you on a blank line.