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: . * check postgrey hiccup Now that we have completed an item, we can finally celebrate: hurray! Well, there is still a bunch of stuff to do anyway. How do we jump to the next outstanding item in the list? Easy: we just look for a "-": /-/ - put rubbish bins outside Yeah, I know, but this is not rubbish-day. Let's look for the next outstanding task: // - buy some coffee Yep! The quite quick combination "//" repeats the last search you did! And we can keep going: // - buy sugar // - make a coffee That's handy, especially since "/" is normally placed in a quite comfortable position in many keyboard layouts. The last example: I have to be honest with you: I can't drink any coffee, so I would like to replace any occurrence of "coffee" with "tea": /coffe/s/coffee/tea/ p - buy some tea The command "/coffee/s/coffee/tea/" is to be read as "look for the next line containing 'coffee' and replace 'coffee' with 'tea' on that line. So what happened here? Let's have a look at the whole file: ,n 1 TODO LIST 2 + phlog about ed(1) 3 - put rubbish bins outside 4 - buy some tea 5 - buy sugar 6 - make a coffee 7 * check postgrey hiccup So, the last search we performed ("//") had set the dot to line 6 ("-make a coffee"). When we issued the substitution command, ed(1) had to look for the next occurrence of "coffee". It wrapped the search around (siince there is no line containing "coffee" after line 6), found "coffee" on line 4, and replaced "coffee" with "tea" on that line. We would like to repeat the last "s" command then, to replace the other occurrence of "coffee" /coffe/s/coffee/tea/ . - make a tea OK, that's powerful, but re-entering the command is not fun. Anyway, we can't learn everything in a single phlog, and this one is already quite long. Let's not forget to save our work: w 121 To be honest with you, I really would like to get rid of that line with "sugar", since I never put any sugar in my tea. But that's a quest for another day :)