paulgorman.org/technical

ed (and a little ex)

Ed is a line-oriented editor. See ed(1).

Although ed is significantly more primitive than screen-oriented editors like vi, it’s still useful for automation and in constrained environments (such as OpenBSD’s single-user mode).

Ed has two modes: command and input. It starts in command mode.

In command mode, ed reads commands from standard input, and executes the commands to manipulate the contents of the edit buffer.

Commands such as “a” (append), “i” (insert), or “c” (change) cause ed to enter input mode. In input mode, ed writes standard input to the edit buffer. Exit input mode with a single period (“.”) on a new line.

All commands operate on an entire line (or multiple lines).

See ed(1) for a complete list of commands.

H    Turn on error explanations
q    Quit
Q    Quit, discarding any unsaved changes
u    Undo last command
w    Write file (Shell magic doesn't work so use "w /home/me/foo.txt" instead of "w ~/foo.txt".)
p    print line(s) (Print all lines like ",p".)
i    Insert before line
a    Append after line
d    Delete line
m    Move line
t    copy line to after line (3t8)
P    Show a Prompt character ("*" by default, or as set on command line with -p flag)

Commands can be prefixed with line numbers, like in sed. Also like in sed, ed addresses are 1-based, so “1p” prints the first line of a file, and “0p” returns “Invalid address”.

% ed
i
In visions of the dark night
But a waking dram of life and light
.
1p
In visions of the dark night
n
1	In visions of the dark night
,n
1	In visions of the dark night
2	But a waking dram of life and light
p
But a waking dram of life and light
n
2	But a waking dram of life and light
1
In visions of the dark night
n
1	In visions of the dark night
2
But a waking dram of life and light
n
2	But a waking dram of life and light
1
In visions of the dark night
a
I have dreamed of joy departed---
foo
.
,n
1	In visions of the dark night
2	I have dreamed of joy departed---
3	foo
4	But a waking dram of life and light
3d
2,3n
2	I have dreamed of joy departed---
3	But a waking dram of life and light
3a
Hath left me broken-hearted
.
2,$n
1	In visions of the dark night
2	I have dreamed of joy departed---
3	But a waking dram of life and light
4	Hath left me broken-hearted
3s/dram/dream/
3p
But a waking dream of life and light
w poe.txt
127
q
%

Moving line:

,n
1       Second line entered
2       The first line entered.
1m2
,n
1       The first line entered.
2       Second line entered

Regular expressions:

g/foo/p    Select lines matching "foo" and print them.
v/bar/p    Select lines NOT matching "bar" and print them.
g/bas/m$   Move lines matching "bas" to end of file.

/foo        Search ahead for lines containing "foo".
?foo        Search backward for lines containing "foo".
s/foo/bar   Substitute first occurrence of "foo" with "bar".
s/foo/bar/g Substitute all occurrences of "foo" with "bar".

Read output of external command into buffer:

r !cal -m

ed one-liners

% echo '/Search string\ni\nEd inserted line\n.\nw' | ed file.txt
% ed -s check_sender_access <<< $'H\n3d\nw'

ed scripts

N.B. — it’s safer to use the stream editor sed where it’s possible to stream-ify the editing task.

Imagine we have a foo.ed text file full of ed commands:

/clusterfuck/s/clusterfuck/incident/
$
a

The end.
.
wq

We can run these commands against a text file:

% ed file.txt < foo.ed

If ed encounters any error — including not finding a search term — it stops execution of the script. In the case of a search, we can have it not stop by prepending the g flag like g/clusterfuck/s/clusterfuck/incident/. Of course, adding the ‘g’ flag causes it to replace all instances rather than just the first.

Again, sed is the safer choice, where possible.

red

If we invoke ed in a Bash script, for example, it may be better to call it as red. red is restricted ed — it only edits files in the current directory and does not execute shell commands.

ex

ex was originally an extension of ed. Nowadays, it’s a shortcut to start vi(m) ex mode. We can use it for one-liners.

The -c flag executes its argument as an ex command, and can be specified up to ten times. Pipe (|) is a command separator, but it doens’t seem to let us put multiple commands in one -c argument.

Insert a line before

% ex -c'/search string' -c'i|My Inserted line' -c'wq' file.txt

We could also source a file full of ex commands:

% ex -c 'source foo.ex' file.txt