MarkdownとBullet Journal

いわゆるプログラマーのつぶやき

edのススメ

エディターとスクリプトの原点

edはUNIXの歴史とともに生まれた。当時はモニターという便利なものは存在せず(コンピューターの出力にTVなどのディスプレイが用いられていなかった)、テレタイプと呼ばれるプリンターの一種で印字していた。

当然ながらedを用いるプログラミングでも、作業対象のファイル内容を確認する手段はcat等を用いての紙への出力しかなかった。

$ cat -n program.c          //# -nは行番号出力指定
1 #include <stdio.h>       //#
2                               //# ファイル内容を印刷
3 int main(void){               //#
4     printf("Hello!¥n");       //#
5  ---                          //#
-
-

これがモニターであれば何行出力しようとも問題ないが、テレタイプを用いての印刷は量が多ければ多量に紙を消費し、印刷時間も膨大にかかる。そのため、当時は確認に必要な分だけを印刷する手法を取った。例えばcatの出力をsedに渡し、sedで範囲を指定すればよい。下記は1〜3行だけを印刷する例である。

$ cat -n program.c | sed -n '1,3p     //# sedで行範囲指定
1 #include <stdio.h>                         //#
2                               //# 1から3行までを印刷
3 int main(void){               //#
$

この様な時代に開発され愛用されたedはラインエディターと呼ばれた。 行番号入力による移動を行い編集モード(標準モード)から挿入モードに切り替えて文字を入力する。

  • 起動と移動方法:
$ ed -p : test.txt    // 後述のexと見た目を合わせたい場合は"-p : "の付加で":"を入力待ち受け記号に出来る
95             // ファイルの文字数が表示される
:                       // 入力待ち
テキストファイルの表示: (以降の入力待ちの表示文字を:とする)

:2,3n            // "2,3"は、2〜3行を対象とする指定で、"n"は行番号付きのprintを示す
2 This is No.2 Line.
3 This is No.3 Line.
:

:2n                     // 行移動は直接行番号を入力
This is No.2 Line.
:
  • 文字入力: aコマンド カーソル行の下に文章を追加
  • 注:下記はカーソルを2行目に移動して入力する例。vi/Vim同様にiコマンドも使える。iコマンドの場合、カーソル行の上に文章が追加される
:2                     // 行移動
This is No.2 Line.
:a                     // "a" (addコマンド)で挿入モードに移行。入力が終わったら"."を入力で編集モードに戻る
This line has been inserted.
The add command can insert multiple lines.     // 複数行の入力が可能
.                   // 挿入モードを抜ける。ここでテキスト入力完了
:

:,n           // 上記の入力を表示
1 This is No.1 line.
2 This is No.2 Line.
3 This line has been inserted.
4 The add command can insert multiple lines.
5 This is No.3 Line.
:

キーボードで一文字入力する毎に、モニターに文字が現れる。当時ならテレタイプが一文字ずつ印字する。ちなみにテレタイプの動作速度は遅く、高速でタイプされると印字が追いつかないこともあったそうだ。

現代のVSCodeVimなどのスクリーンエディターは画面上のどこでも自由に移動(編集)できる。しかし、テレタイプは次の文字を打つための横移動やLFしか行えず、また紙に一旦印刷された印字は元に戻せない制約から、当時のエディターはラインエディターがベストな選択だったのだ。

なおラインエディターの名称からライン、つまり一次元の横方向の移動は自由に行える様に思えるが、前記の通りテレタイプは印字位置を任意に動かせないので、挿入モードでは次の文字の入力しか出来ない(但しGNU edなど最新のedは行単位での修正が可能)。では修正や挿入、削除はどうするのか。これらは編集モードに戻って行単位での変更、置換、削除などを行う。

  • 行の削除: 行単位で削除となり文字や単語単位の削除は出来ない(後述の置換は可能)
:d                     // カーソル行を削除
:
:4d           // 4行目を削除
:
:2,25d                 // 2〜25行をまとめて削除
:
  • 行の変更: cコマンド 指定行を削除して新しい文章を挿入(複数行可能)。
:,p           // 変更前を表示
This is No.1 line.
This is No.2 line.
This line has been inserted.
The add command can insert multiple lines.
This is No.3 line.
:

:4,5c                  // 4〜5行目を削除して新たな行と入れ替える
This is No.4 line.
.                      // テキスト入力完了

:,p                    // 変更後を表示
This is No.1 line.
This is No.2 line.
This line has been inserted.
This is No.4 line.
:
  • 置換: sコマンド s/old/new/で、oldをnewに置き換える。この置換は、行単位で一番最初に一致した文字列のみ置換するので、一致する文字列を全て変換する場合はgオプションが必要。s/old/new/g
$ ed -p : program.c                    # edを起動(プロンプト文字に:を指定)
156                                    # ファイルの文字数出力
:4n                                    # 4行目のみ出力(印字)を指示
4     printf("Hello!¥n");              # 4行目印字
:s/Hello/Good morning/p                # HelloをGood morningに修正
4     printf("Good morning!¥n");       # 内容が更新された
:
  • 検索: 後方検索時は"/文字列"と入力。前方検索時は"?文字列"と入力。
  • 保存: wコマンド vi同様。変更内容を保存。ファイル名を指定するとそのファイル名で保存。
  • 終了: qコマンド vi同様。(強制終了は大文字のQ)
:w                   // 保存コマンド
126                  // 保存された文字数が表示される

:q                   // 終了コマンド (wqと打てば保存終了)
$

上記の置換sコマンドの使い方はsedの置換によく似ている。 そう。edはex, vi, Vim, Emacs, VSCodeと発展してきたエディターのご先祖様であると同じく、sed, awk, perl, ruby, PHP, Pythonなどのスクリプトの先祖でもあるのだ。

よってedを使うとその後発展した各プログラムの基礎を学べるとも言えよう。ちなみに私は一画面程度で収まる様なスクリプト作成では時々edを使っている。歴史やラインエディターの特性を知った上でedを使っていると、出力がモニターにも関わらずテレタイプで印字している錯覚を覚え、印字量を最小に押さえる工夫も自然と行う様になる。

いやいや、無尽蔵にPCのリソースを使える現代に於いてあまりにも時代錯誤な話ではないかと考える方も多いかもしれない。しかしedや直系の子孫であるvi/Vimを使い続けると心構えが徐々に変化し、最適な移動コマンドを駆使する様になり、結果として高品質なドキュメントを短時間で作成できる様になる。

もしあなたがミニマリストであればきっと気に入るだろう。 機会があればedを堪能して欲しいと思う。