There's an old joke you've probably heard: "ed is the standard unix text editor", which is kind of a joke third-party position in the editor war. If you've ever gotten curious and run ed, probably something like this happened (text in strong is typed, normal text is output by ed):
$ ed help ? ? ? quit ? ^C ? ^D $
You'll notice that ed is extremely terse. It comes from the bad old days when each character of output had to come through a clunking line printer, so ed generally doesn't say anything it doesn't have to. Fortunately, ed has a 'helpful' mode, which you can turn on by typing 'H':
$ ed H help ? invalid command suffix
Ok, so it could be more helpful, but it's better than just '?' at least.
Like other editors, ed is oriented around editing buffers, which might be backed by files or might just be kept in memory. At any given time, ed has only one buffer - there's no support for editing multiple documents simultaneously or anything similar.
Most editors are visual editors, in which the editor always displays the contents of the buffer, and you can make edits directly to the displayed text. Some well-known visual editors are emacs and vim (which is actually a distant descendant of ed). In contrast, ed is a line editors, in which the buffer isn't continuously displayed, and you edit the buffer by typing commands that manipulate the text in the buffer. For example, you might type a command for "delete the first four characters of line 3", and the editor would carry that out without displaying the actual text at any point. This makes ed quite friendly for low-bandwidth or low-resource systems.
So, let's go about getting to grips with ed a bit. Since ed is a line editor, every ed command is tagged, either implicitly or explicitly, with which lines it's supposed to operate on. You can address lines a bunch of ways but the most common ways are:
Each command in ed needs either zero addresses, for commands that affect the whole file, one address for commands that affect a single line, or two addresses for commands that affect a range of lines. Commands that take a line range can by given only one address, in which case the range is just that line. Here are some of the basic commands:
Let's try these commands out a bit:
$ ed 0a Hello, ed tutorial readers! This is some text in insert mode. Insert mode is ended with a ".". . 1,$n 1 Hello, ed tutorial readers! 2 3 This is some text in insert mode. 4 Insert mode is ended with a ".". 3a This is a line being appended after line 3. . 1,$n 1 Hello, ed tutorial readers! 2 3 This is some text in insert mode. 4 This is a line being appended after line 3. 5 Insert mode is ended with a ".".
Here we can see some examples of what adding text to a file is like. If we had run ed with a filename, it would have loaded that file into its initial buffer.
There's a couple more things we're going to need, though. What if we make a mistake? Within a line, we can backspace and type new text, but already- typed lines need something else to edit them. Enter the d and s commands!
Let's play with the new toys a bit:
$ ed 0a This is another example. Oh, this line was a mistake! And this line has a tyop. . 1,$n 1 This is another example. 2 Oh, this line was a mistake! 3 And this line has a tyop. 2d 1,$n 1 This is another example. 2 And this line has a tyop. 2s/tyop/typo/ 1,$n 1 This is another example. 2 And this line has a typo.
So here we can see how to delete whole lines and change individual parts of lines. We can also use the s command for other things, using the ability to address many lines:
$ ed 0a This is the first line. This is the second line. Is this the third line? . 1,$n 1 This is the first line. 2 This is the second line. 3 Is this the third line? 1,$s/^/-> / 1,$s/$/ <-/ 1,$n 1 -> This is the first line. <- 2 -> This is the second line. <- 3 -> Is this the third line? <-Here we're making good use of the two-address form of s, using "1,$" to mean "the first line to the last line" - i.e., the whole buffer. In fact, addressing the whole buffer is so common that there's a special address for it: "%" is a shortcut for "1,$".
So we've written some text in our buffer, but how do we actually save it? Enter the w command. The w command takes two addresses, but if no addresses are given it defaults to "1,$". It also takes a filename after the command, which is where the addressed lines are written to. If ed was started with a filename, w will default to writing to that filename if no filename is given with the command. It has a counterpart command, r, which takes one address and reads the named file after the addressed line. Let's play with that:
$ ed 0a This is the first line. This is the second one. It will look pretty in a file! This is the third line. . 2,$w example.txt 79 3r example.txt 79 1,$n 1 This is the first line. 2 This is the second one. It will look pretty in a file! 3 This is the third line. 4 This is the second one. It will look pretty in a file! 5 This is the third line.Note that after ed reads or writes a file, it says how many bytes it read or wrote.
The last thing we need to learn how to do is quit! The q command quits ed, although it will error once if you have a buffer that hasn't been written - in that situation, running q again will quit ed anyway. Since writing to an edited file and quitting is a very common operation, ed has a shortcut command wq that writes and quits.
So, let's review: