ed(1) is The Right Tool    
                =============================

You know: ed(1) is the standard text editor [1], and indeed you would
find ed(1) installed in any unix-like system. But I guess most Unix
users have never actually tried to open it. The reason is probably that
ed(1) is considered "hard-to-use" and "user-unfriendly". I really see no
reason for such misconceptions and no motivation for their popularity,
so I will try to convince you with concrete examples and scientific
evidence that ed(1) is, almost always, The Right Tool to use. 

This tutorial was originally publised as a series of "phlog" posts (a
blog over gopher), in the hope to serve as an "ed-primer" for beginners.
The eight posts are reported below in the same order as they appeared in
the phlog. The only addition is the last paragraph of Section VII, which
was not present in the initial series of phlogs. The references of each
section are reported at the end of the section.

If you are in a rush and would like to go a proper book, look for the
great "Ed Mastery" by Michael Lucas [2].

KatolaZ

   ed(1) is The Right Tool (I)   
=================================

First things first: ed(1) is a line editor, meaning that it acts on a
line at a time. This is something we are not used to anymore, since our
glass-terminals have allowed full-screen character-based editors to
evolve. But on teletypes line-based editing makes a lot of sense. This
means that we need to tell ed(1) which line we would like to edit and
what to do on that line.  

In this tutorial we will use ed(1) to compile and manage simple TODO
lists. This will allow us to explore almost all the ed(1) commands. 



Let's start by creating the file "TODO.txt" with ed(1):

  $ ed TODO.txt
  TODO.txt: No such file or directory


Well, welcome to ed(1), aka "The Faithful Silent Servant of Unix masters
of old". ed(1) is telling you that it could not find any file named
TODO.txt in the current directory (and this is something we knew
already) and then it prints a new-line to signal that it is ready to
receive commands. Yes, ed(1) has no default "prompt". Actually, it does,
and the prompt is just "no-character-at-all". Now let's add a few items
to our TODO.txt list:

  0a
  TODO LIST
  - phlog about ed(1)
  - put rubbish bins outside
  - make a tea
  - check postgrey hiccup
  .


The first line "0a" tells ed(1) that I want to "a-ppend" lines after the
0-th line. Now, the 0-th line actually indicates the start of the
buffer. ed(1) accepts my command and waits for the lines to be inserted
there. It will keep receiving lines until you input a line containing
only a "." (dot) [3].  Then ed(1) will "print" its prompt (which is
indeed "no-character") and wait for the next command. Let's ask ed(1) to
"p-rint" the whole TODO list then:

  ,p
  TODO LIST
  - phlog about ed(1)
  - put rubbish bins outside
  - make a tea
  - check postgrey hiccup


(notice the ed(1) prompt on the last line!). The command "p" is used to
print lines. It is normally put after the specification of a range of
lines, but in this case "," indicates the range "from the first line
down to the last one". Now what happens if you type "p" alone?

  p
  - check postgrey hiccup


(notice again the ed(1) prompt above). Well, any command in ed(1)
modifies the "current line address", which is the line any ed(1) command
would implicitely work on if you don't provide any line to it. The
command "p" moves the current address to the last line it printed. So
",p" moved the current address to the last line of the buffer, and the
following "p" just printed the current line (the last one). 

Another useful command is "n", which prints lines adding line numbers:

  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - make a tea
  5       - check postgrey hiccup
 

Oh now that's convenient! Guess how you ask ed(1) to print the third
line in your buffer:

  3p
  - put rubbish bins outside
  
  
While you can use the special marker "$" to indicate "the last line in
the buffer":

  $n
  5       - check postgrey hiccup
  
 
Notice that there is no space between line ranges and the command that
applies to them. I guess you have had enough ed(1)-ting for today, and I
am not in the right mood to start working at this todo-list now. So
let's just save our work for later:

  w
  94


ed(1) prints the number of bytes written in the file TODO.txt. We can
now exit ed(1):

  q
  $

and you are back to the shell prompt. Now you can see your brand-new
TODO list with:

  $ cat TODO.txt
  TODO LIST
  - phlog about ed(1)
  - put rubbish bins outside
  - make a tea
  - check postgrey hiccup
  $

or by using:

  $ printf ",p\n" | ed TODO.txt
  94
  TODO LIST
  - phlog about ed(1)
  - put rubbish bins outside
  - make a tea
  - check postgrey hiccup
  $

;-)
 
 -+-+-+-

ed(1) was included in Unix-V1 (1971) and was used to write the Unix
      kernel and all the programs distributed with Unix at least until
      Unix-V7 (1979)

 -+-+-+-
 
[1] https://www.gnu.org/fun/jokes/ed-msg.html
[2] https://www.tiltedwindmillpress.com/product/ed/
[3] I use a dash "-" to indicate tasks that are still outstanding, a
    plus "+" for tasks I have started working on, and a star "*" for
    completed tasks.


   ed(1) is The Right Tool (II)   
==================================

Let's get on with our mission of learning the basics of ed(1), the
standard text editor of the unix environment.

In the first installment of this mini-series of phlogs [1] we saw a few
basic commands to add some lines ("a"), print lines ("p", "n") and save
a file after you are done ("w"). Using those commands we were able to
compile a simple TODO list:

  $ ed TODO.txt
  94
  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - make a tea
  5       - check postgrey hiccup

Now imagine that we want to insert a new item (buy some tea) just before
the line that reminds us to make a tea. We will use the command "i" (for
"insert"):

  4i
  - buy some pea 
  .
  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - buy some pea
  5       - make a tea
  6       - check postgrey hiccup

Easy, right? While "a" is used to "append" lines after a given line, "i"
is instead used to "insert" lines before a given line. As with "a", the 
"i" commands is ended by a line containing only a ".". If you have ever
used vi(1) or one of its many clones, you know that "i" is also the
command needed to move to "insert" mode in vi(1). Well, this is not a
coincidence.

Notice that when we inserted the new line we also introduced a typo: we
definitely want to buy some "tea" (not a "pea"). We can "change" the
content of a line using the command "c":

  4c
  - buy some tea
  .
  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - buy some tea
  5       - make a tea
  6       - check postgrey hiccup

Notice that ed(1) acts consistently: the three commands used to append,
insert, or change lines are all terminated by a line containing a single
".". Actually, the command "c" in general allows us to replace one line
(or a range of lines) with another line (or with a range of lines). So
if you prefer coffee instead of tea you might use:

  4,5c
  - buy some coffee
  - buy sugar
  - make a coffee
  .
  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - buy some coffee
  5       - buy sugar
  6       - make a coffee
  7       - check postgrey hiccup

Well, it's evident that having to retype a line just to correct a typo
is not exactly what one would call an efficient editing session. Indeed,
the command "c" is mostly used when the content of a range of lines has
to be substantially modified. Luckily, ed(1) has another command ("s",
for "substitute") which allows to easily correct typos, as well as to
perform complicate substitutions across any range of lines. That will be
the focus of the next phlog in this series :)

 -+-+-+-

[1] gopher://republic.circumlunar.space/0/~katolaz/phlog/20190505_ed_lists.txt



   ed(1) is The Right Tool (III)
===================================

A todo-list is useful if you start working on the items and you are
eventually able to remove some items from the list, sooner or later...

Our current list looks like this:

  ,n
  1       TODO LIST
  2       - phlog about ed(1)
  3       - put rubbish bins outside
  4       - buy some coffee
  5       - buy sugar
  6       - make a coffee
  7       - check postgrey hiccup

Now it is clear I have started phlogging about ed(1), so the first item
should somehow be updated. I have come up with a simple convention to
identify the status of items in a todo-list, by using the first
character of the item: a "-" indicates an outstanding item, a "+"
indicates something I have started working on, and a "*" marks a
completed item. In this case, I would like to change the "-" in the
first item with a "+". Let's start searching for the line where I
mentioned "phlog":

/phlog/
- phlog about ed(1)

Yep. An expression like "/expr/" is used in ed(1) to search for a
pattern. ed(1) search for the first occurrence of that pattern and
prints it. Most versions of ed(1) will also wrap the search around and
start from the beginning if they reach the end of the file. Now the
current line (the so-called ".") is the one containing the item I want
to edit. Let's "substitute" the first "-" in the line with a "+":

s/-/+/
p
+ phlog about ed(1)

Yeah, it's that simple. The command "s" (for "substitute") replaces the
first occurrence of the pattern between the first pair of "/" following
it with the pattern between the second pair of "/" following it. In this
case, we simply replaced "-" with "+". 

The command "s" accepts a line (or a range of lines) to work on. So if
we are indeed working on all the items in the todo-list, you can change
their state with a single command:

1,$s/-/+/
,p
TODO LIST
+ phlog about ed(1)
+ put rubbish bins outside
+ buy some coffee
+ buy sugar
+ make a coffee
+ check postgrey hiccup

Well, that's powerful, right? But in my case, well, it's not true, since
I have not put the rubbish outside and some other items are in a
different state. Let's revert out last change:

u
,p
TODO LIST
+ phlog about ed(1)
- put rubbish bins outside
- buy some coffee
- buy sugar
- make a coffee
- check postgrey hiccup

The command "u" (for "undo") will do that (i.e., revert the effect of
the last command). Try to see what happens if you keep pressing "u" :)

The cool thing about "s" is that the line it has to act upon can be
expressed with a pattern. For instance, I have solved the hiccup in
postgrey, so I can change the status of the line containing "postgrey"
to "done" by replacing the leading "-" with a "*". But I don't remember
which line is it, so I can use the command:

/postgrey/s/-/*/
,p
TODO LIST
+ phlog about ed(1)
- put rubbish bins outside
- buy some coffee
- buy sugar
- make a coffee
* check postgrey hiccup

Remember that the "." is set at the last edited line: