ed(1) is The Right Tool (IV)
==================================
Let's have a look at our current TODO list:
$ ed TODO.txt
121
,p
TODO LIST
+ phlog about ed(1)
- put rubbish bins outside
- buy some tea
- buy sugar
- make a tea
* check postgrey hiccup
I need to add a couple more items to the list. Let's do it:
a
- find the sugar pot
- configure Unix V7 outpost
- read Shismatrix
.
First, there is a typo:
s/Shi/Schi/
.
- read Schismatrix
Then, as I said in the last phlog, I really would like to get rid of
sugar. Really. I need to "delete" all the lines containing "sugar" (and
I have just inserted another one!). If "i" is for "insert", "a" is for
"append", "c" is for change, "p" is for "print", "s" is for
"substitute", what do you expect to be the command to "delete"? Yes,
indeed, the ed(1) command for "delete" is "d", and it requires either an
address or a pattern. Let's give it a try:
/sugar/d
,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
7 - find the sugar pot
8 - configure Unix V7 outpost
9 - read Schismatrix
Wow. The line saying "- buy sugar" has disappeared. Let's undo, and try
something else:
u
5d
,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
7 - find the sugar pot
8 - configure Unix V7 outpost
9 - read Schismatrix
Same outcome! So you can delete a line by using the command "d" and
specifying either a line number or the pattern that the line should
match. Cool, but sometimes impractical, especially if you have lots of
"sugar" you want to get rid of. There is obviously an efficient
ed(1)-way of dealing with that. In order to have something non-trivial
to work on (i.e., more than one line containing "sugar"), we first
"undo" the last change, so that all the "sugar" reappears:
u
,n
1 TODO LIST
2 + phlog about ed(1)
3 - put rubbish bins outside
4 - buy some tea
5 - buy sugar
6 - make a tea
7 * check postgrey hiccup
8 - find the sugar pot
9 - configure Unix V7 outpost
10 - read Schismatrix
What if we want to print all and only the lines containing "sugar"? We
know that the simple search command "/sugar/" won't work, since it
prints only the next matching line and then stops. Let's try someting
more powerful:
g/sugar/p
- buy sugar
- find the sugar pot
We have just used the "global" ed(1) command, indicated by "g". This
command looks for matches of the pattern immediately following it (in
this case, the pattern is "sugar") and then executes the command
indicated right after the pattern itself (in this case, the command is
"p" for "print"). So what we have just done is a specific instance of
"g/RE/p", which looks for all the lines matching the regular expression
"RE" and prints them. Yes, this is exactly where the Unix command
grep(1) comes from! [1]
The nice thing about the global command is that it can be followed by
literally any other ed(1) command. So if we need to delete all the
lines containing "sugar", we just give:
g/sugar/d
,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
7 - configure Unix V7 outpost
8 - read Schismatrix
Now we are talking. This could have become the "gred" command, but the
sage dwarves at Murray Hill noticed that it would have been better to
have a generic tool to handle generic stream-oriented editing, and the
Unix command sed(1) was born instead [2]. Before we save the todo-list,
I need to note that I have started working on two items, namely those on
line 7 and line 8 (yes, I am indeed putting up an outpost with a working
Unix V7 machine for general use, and I need a good name for it, possibly
from the Schismatrix universe :P):
g/ix/s/-/+/
,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
7 + configure Unix V7 outpost
8 + read Schismatrix
Can you see why the global command did exactly what we expected it to
do? Let's dissect it. We asked ed(1) to look globally for the pattern
"ix" (g/ix/), and to substitute a "-" with a "+" in the matching lines
(s/-/+/). Easy, right? Let's save our work now.
w
156
q
-+-+-+-
[1]
http://www.catb.org/~esr/jargon/html/G/grep.html
[2]
http://www.cs.dartmouth.edu/~doug/reader.pdf