sebastiano.tronto.net

Source files and build scripts for my personal website
git clone https://git.tronto.net/sebastiano.tronto.net
Download | Log | Files | Refs | README

commit 8eb8874002454c8638e26bd3bca9eaa174c2ef54
parent 1b69fbdce80f4ee2d46be63be34b4cfb4e4e11d7
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Sat, 24 Dec 2022 13:08:45 +0100

Added blog post

Diffstat:
Asrc/blog/2022-12-24-ed/ed.md | 421+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/blog/blog.md | 1+
Msrc/blog/feed.xml | 7+++++++
3 files changed, 429 insertions(+), 0 deletions(-)

diff --git a/src/blog/2022-12-24-ed/ed.md b/src/blog/2022-12-24-ed/ed.md @@ -0,0 +1,421 @@ +# The man page reading club: ed(1) + +I enjoyed writing a little introduction at the beginning of every +post of this series, but I am running out of ideas. I am not much +of fiction writer. I'll skip this time, maybe I'll get back to doing +it in the future. + +For this episode I chose to explore ed, +[the standard editor](https://www.gnu.org/fun/jokes/ed-msg.en.html). +This little piece of software first appeared in the very first +version of UNIX, in the late '60s. Back then, the most common way +to interact with a computer was via a +[teletype](https://en.wikipedia.org/wiki/Teleprinter). This meant +that, in order to edit a file, you could not simply show a screenful +of text and modify it interactively. + +As we will see in this post, the way you modify your text files +with ed is by running commands, as you would in your usual +[shell](../2022-09-13-sh-1). You might wonder why in the world you +should be interested in using this over a more human-friendly text +editor. There are at least a couple of reasons: + +1. You find yourself in a very limited environment (e.g. some ebedded + OS) where ed is the only editor available. +2. You want to edit a text file as part of a shell script - you can + find an example in my [last blog entry](../2022-11-23-git-host). + +## ed(1) + +*Follow along at +[man.openbsd.org](http://man.openbsd.org/OpenBSD-7.2/ed)* + +The first section explains a few fundamental things. + +First of all, ed can be invoked with a file as an argument. The +given file is copied into a *buffer*, and changes are written to +it only when the user issues a `w` command. + +ed reads every line the user inputs and tries to interpret it as a +command. The general form for an ed command is + +``` + [address[,address]]command[parameters] +``` + +Where the (optional) addresses specify a range of lines over which +the command has to operate. See the **Line addressing** section +below for more info. + +Some commands allow you to switch to *input mode*, where ed reads +text without trying to interpret it as a command - usually for the +purpose of inserting it in your file - until a line with a single +dot `.` character is read. + +There are only two command line options for ed: `-s` to suppress +diagnostic messages and `-p prompt` to specify a prompt string for +its command line. + +### Line addressing + +Every command operates on one or more lines. The default is the +*current line*, which is usually set to be the last line affected +by the last command. For example, after opening a file, the current +line is set to its last line. + +You can specify the line(s) on which a command shall operate by +prepending one or two *addresses* separated by a comma or a semicolon. +The difference is the following: + +``` + Each address in a comma-delimited range is interpreted relative to the + current address. In a semi-colon-delimited range, the first address is + used to set the current address, and the second address is interpreted + relative to the first. +``` + +For example, let's say you are on line 3. Then the address range +`5,+4` selects the lines from 5 to 7 (3+4), while `5;+4` selects 5 +to 9 (5+4). + +But what is a valid address, actually? Besides simply specifying a +line number, there are a variety of ways to address line: For +example, `.` refers to the current line and `$` to the last line +of the file. As we have seen, you can also specify relative addresses +in the form `-n` or `+n`. You can also search for a line containing +a specific patern: + +``` + /re/ The next line containing the regular expression re. The search + wraps to the beginning of the buffer and continues down to the + current line, if necessary. The second slash can be omitted if + it ends a line. "//" repeats the last search. +``` + +For more infor about regular expressions, see +[re_format(7)](http://man.openbsd.org/re_format) +(or perhaps my next blog entry?). Using question marks instead of +slashes (like this: `?re?`) searches backwards. + +### Commands + +ed offers a lot of commands to manipulate text. If you are familiar +with other UNIX editors such as vi or sed, you may recognize many +of them. + +As usual, they are listed in alphabetic order in the manual page, +so I took the liberty of re-arranging them into groups. I'll have to +skip or just briefly mention some of them, otherwise I might just +as well copy the whole manual page here. + +**Address-only commands** + +Specifying an address only, without a command, changes the current +line to the (last) addressed line and it prints it. The default is +the next line, i.e. if you just press enter ed prints out the next +line and sets it as the current line. + +**Printing lines** + +The command `p` prints the addressed line. The command `n` does the +same, but it also prints line numbers. `l` is the same as `p`, but +special characters (e.g. new lines) are made visible. + +Most commands accept a *print suffix* `p`, `l` or `n` that instructs +ed to print the last line affected by the command. Thus, the three +printing commands can be also seen as an *address-only command* +followed by a print suffix. + +**Basic editing** + +The commands `a` and `i` toggle *input mode* to let you insert text +after (**a**ppend) or before (**i**nsert) the last line addressed. +Usually you want to address a single line, often the current line, +when using one of these commands. + +The commands `d` and `c` can be used to **d**elete or **c**hange +the addressed lines. The latteris equivalent to `d` followed by an +`a` command. + +**Copying, moving and joining lines.** + +The commands `t` and `m` operate on a range and take an extra single +address (which can be `0`) as a parameter, and copy (**t**ransfer) +or **m**ove the addressed lines to that location. For example the +command `2,4t0` will copy the 2nd, 3rd and 4th lines to the beginning +of the file. + +If you want to join multiple lines in one you can use the `j` command. + +**Text substitution** + +The `s` command is one of the most powerful ed offers, but also one +of the most complex. It allows you to replace a piece of text, or +any arbitrary pattern defined by a regular expression, with whatever +you like. + +It comes in three variants: + +``` +(.,.)s/pattern/text/ +(.,.)s/pattern/text/g +(.,.)s/pattern/text/n +``` + +Where `pattern` is a regular expression and `text` is simple text. +The first form replaces only the first occurrence of `pattern` in +each selected line, while the second replaces every occurrence. In +the last form, `n` must be a number, and only the n-th occurrence +is replaced. + +There are some special characters that can be used: for example, a +single `&` in `text` is equivalent to the currently matched text. +If `text` consists of a single `%`, the `text` argument of the last +`s` command issued is used. + +You may escape any character in `text`, including newlines, by +prepending a backaslash. To avoid escaping slashes to death, keep +in mind that you can use any other character, for example a `|`, +instead of `/` in the `s` command. + +Finally, a simple `s` command, without pattern or text, repeats the +last substitution issued. + +Let's put this all together with a single example. We have a file +that looks like this: + +``` +This is the first line +Another line, called the second line +/A third line, with boundaries/ +Let's make it four +``` + +And run the following ed commands: + +``` +1/s/t/T/ +1/s/T/&&/g +2/s/l/%/ +1,3s +3s|/|\||g +``` + +The result is: + +``` +TThis is TThe first lline +Another llline, called the second line +|A third lline, with boundaries| +Let's make it four +``` + +Understanding why you get this is left as an exercise for the reader ;-) + +**Multiple commands on selected lines** + +The commands `g` and `G` are also quite powerful. With + +``` +(.,.)g/pattern/command-list +``` + +you can specify a list of commands to be executed on every line +matching the regular expression `pattern`. The commands in the list +are each on their own line, ended with a backslash. The command `G` +is essentially an interactive version of `g`. Check the man page +for more details! + +**Marks** + +You can mark a line with a single lowercase letter (say x) using +the command `[address]kx`. What for, you might ask? Well, when +talking about addresses I omitted to tell you that you can also +refer to a marked line using `'x`. You only have 26 marks at your +disposal, and one is only deleted when the line it marks is modified, +so use them wisely! + +**Reading files and commands** + +You can use the `r` command to insert the content of a file (with +`r filename`) or the output of a command (with `r !command`) after +the current line. This is the same as the `r` command of vi, which +I have discussed in a [previous blog entry](../2022-09-05-man-col). + +**Undo** + +Use the `u` command to undo the last command. Using `u` twice +undoes the undo. No editing history for you, sorry. + +**File management** + +From inside ed, you can use `e filename` to open a new file (**e**dit), +`w` to save your changes to the current file (**w**rite) and `q` +to quit. These commands have an upper-case variant (`E`, `W`, and +`Q`) that can be used to ignore errors (e.g. quit without saving). + +The command `wq` can be used as a shortcut for saving and closing. + +### ? + +ed is infamously terse with its error messages. Indeed, whatever +error you make, you are going to be faced with the following +informative line: + +``` + ? +``` + +But don't worry: the command `h` shows a more verbose description +of the last error. You can use the `H` command to toggle verbose +error messages for the whole session. + +## An example session + +Let's write an *Hello world* text file using ed! + +Let's start by calling ed with a reasonable prompt, to make our +life easier. + +``` +$ ed -p 'ed > ' hellow.txt +``` + +And let's open a (new) file: + +``` +ed > e hellow.txt +``` + +Don't worry about the (unusually verbose!) error message. The file +does not exist yet, but it will be created when we save our work +with `w`. Now let's add a line of text: + +``` +ed > a +Hello, wolrd! +wq + +``` + +Wait, why is ed still open? And why is it not showing the `ed > ` +prompt? Oh right, we forgot to end the input mode by entering a +single dot! + +``` +. +ed > +``` + +Ok, now we are back in business. But we have to remove the `wq` +line we entered by mistake: + +``` +ed > /wq/d +``` + +Let's check that we have written what we intended to by printing +the content of the file: + +``` +ed > 1,$n +1 Hello, wolrd! +``` + +Oh no, there is a typo! No big deal, we can fix it: + +``` +ed > 1s/lr/rl/ +``` + +And now that we are done, we can close our file: + +``` +ed > q +? +``` + +Wait, what's going on? Let's check: + +``` +ed > h +warning: file modified +``` + +Oh right, we need to save. + +``` +ed > wq +``` + +And now we are done! + +## I/O redirection magic + +As all other basic UNIX utilities, ed can be used non-interactively +by using input / output redirection. As an example, consider the +interactive session above. The input we fed to ed was: + +``` +e hellow.txt +a +Hello, wolrd! +wq +. +/wq/d +1,$n +1s/lr/rl/ +q +h +wq +``` + +If we save (a stripped down version of) the text above in a file +called `edcommands.txt` + +``` +a +Hello, wolrd! +wq +. +/wq/d +1s/lr/rl/ +wq +``` + +and run + +``` +$ ed -s hellow2.txt < edcommands.txt +``` + +We should obtain a file `hellow2.txt` identical to `hellow.txt`. I +say "should" because apparently there is a little caveat: when used +non-interactively, ed exits on the first error it encounters. This +also happens with the `No such file or directory` error that we get +at the beginning, if a file `hellow2.txt` does not exist yet. We +just have to create one in advance, for example with `touch +hellow2.txt`, and run again the ed command above. + +## Conclusions + +ed was designed in a time when the computer-human interaction was +a bit different from now, and it shows. However, its language is +pleasantly consistent: every action you want to perform is expressed +in the address-command-parameters form. This makes it easy to learn +and boring, which is a good thing. Such consistency is much harder +to achieve in the 2D graphical world - which includes +[TUIs](https://en.wikipedia.org/wiki/Text-based_user_interface). + +At the beginning of the post I have mentioned two use cases for a +software like ed in the present day: being forced into a limited +environment and using it in non-interactive mode. But there is at +least another one: for visually impaired users, modern computer +interfaces are largely inaccessible, as they can't look at a wall +of text and pictures to figure out where the stuff they want to +work on is. On the other hand, an editor like ed does not overwhelm +users with visual output and does not require them to keep in mind +more than one line at the time. If you are interest in this topic +I highly suggest reading the article +[The command line philosophy](http://www.eklhad.net/philosophy.html) +by Karl Dahlke, the author of [edbrowse](https://edbrowse.org). diff --git a/src/blog/blog.md b/src/blog/blog.md @@ -2,6 +2,7 @@ [RSS Feed](feed.xml) +* 2022-12-24 [The man page reading club: ed(1)](2022-12-24-ed) * 2022-11-23 [Self-hosted git pages with stagit (featuring ed, the standard editor)](2022-11-23-git-host) * 2022-10-19 [Keeping my email sorted (the hard way)](2022-10-19-email-setup) * 2022-10-01 [The man page reading club: tetris(6)](2022-10-01-tetris) diff --git a/src/blog/feed.xml b/src/blog/feed.xml @@ -9,6 +9,13 @@ Thoughts about software, computers and whatever I feel like sharing </description> <item> +<title>The man page reading club: ed(1)</title> +<link>https://sebastiano.tronto.net/blog/2022-12-24-ed</link> +<description>The man page reading club: ed(1)</description> +<pubDate>2022-12-24</pubDate> +</item> + +<item> <title>Self-hosted git pages with stagit (featuring ed, the standard editor)</title> <link>https://sebastiano.tronto.net/blog/2022-11-23-git-host</link> <description>Self-hosted git pages with stagit (featuring ed, the standard editor)</description>