MarkdownとBullet Journal

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

edのススメ

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

f:id:ProgrammingForEver:20210922212703j:plain

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    # 起動時に"-p : "と打つと":"を入力待ち受け記号に出来る
95               # 起動時にファイルの文字数が表示される
:                       # 入力待ち
テキストファイルの表示: (以降の入力待ちの表示文字を:とする)

:,n              # ","は全体を表し、,pは全行、,nは行番号付きで全行をprintする
1 This is No.1 Line.
2 This is No.2 Line.
3 This is No.3 Line.
:

:.                      #  "."は現在行をprint
3 This is No.3 Line.
:

:2,3n            # "2,3"は、2〜3行を対象とする指定で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             # 上記の入力結果をprint
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に修正、pは結果をprint指示
4     printf("Good morning!¥n");       # 内容が更新された

:,s/a/b/g                              # 全行対象にする時は",s"にする。gは行の中の対象を全て置換
  • 検索: 後方検索時は"/文字列"と入力。前方検索時は"?文字列"と入力。
  • 保存: 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を堪能して欲しいと思う。以下、コマンドの整理:

- .n 現在行を番号付きで表示
- ,n 全て番号付きで表示
- ;n 現在位置から全て番号付きで表示
- 500,510n : 500行から510行まで番号付きで表示.

- z 現在位置から一画面分表示
- 500z4n : 500行から4行分を番号付きで表示

- a 現在行のに新しい行を挿入して編集
- i 現在行のに新しい行を挿入して編集
- c 現在行を削除して新しい行を挿して編集.
- . 編集を終える(edのコマンドプロンプト表示)

- 500m520 : 500行を520行の下に移動
- 200,210m0 : 200から210行をfileのtopに移動
- 400d : 400行を削除
- 600,610d : 600から610行を削除
- 500r dummy.txt : 指定した行の下に指定fileを挿入
- 300,305j : 300から305行までを一行に連結
- 200t300 : 200行を300行の下にコピー
- 100,120t400 : 100から120行を400行の下にコピー
- 510,530w dummy2.txt : 指定した行を含む新fileを作る
- f dummy3.txt : 現在のbufferを保存するfile名を与える。wqで保存
- e dummy4.txt : 指定したfileに切り替える。bufferが飛ぶので注意

- ka,kb,kc,,,  : bookmark set
- 'a,'b,'c,'d,,, : bookmark call
- u : undo

なおMacでは正規表現の¥+などが効かない。

Msys2からed追加:Windows Git Bashに不足しているコマンドを追加する方法

$ zstd -d ed-1.17-1-x86_64.pkg.tar.zst
bash: zstd: command not found
  • Git for Windowsにzstdが無い
  • WSLでもzstdが無く、sudo apt しようとしたらパスワードが分からない・・
  • 仕方なくUbuntuを再インストール、しかし今度は下記のエラーになる
$ sudo apt install zstd
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package zstd

解決方法は実にあっさりとしたもので、aptをアップデートすればよい。

# sudo apt update

WSLのホームディレクトリの場所@2019

WindowsUbuntuWSL

  • WSLのホームディレクトリがアップデートで変わった。 18.04ならここ
  C:\Users\[ユーザー名]\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home
  • ここにfileを移動する。chmodしてからzstd。続いてtarを実行。
$ zstd -d ed-1.17-1-x86_64.pkg.tar.zst
zstd: ed-1.17-1-x86_64.pkg.tar.zst: Permission denied
$ chmod 777 ed-1.17-1-x86_64.pkg.tar.zst
$ zstd -d ed-1.17-1-x86_64.pkg.tar.zst
ed-1.17-1-x86_64.pkg.tar.zst: 102400 bytes
$ tar -xvf ed-1.17-1-x86_64.pkg.tar
.BUILDINFO
.INSTALL
.MTREE
.PKGINFO
usr/
usr/bin/
usr/bin/ed.exe
usr/bin/red
usr/share/
usr/share/info/
usr/share/info/ed.info.gz
usr/share/man/
usr/share/man/man1/
usr/share/man/man1/ed.1.gz
usr/share/man/man1/red.1.gz
  • ここで得られたedをGit下のusr/binにコピー。しかし何故かパスが通らない(実行はOK)ため.bashrcを編集してOK
alias ed='c:/Git/usr/bin/ed -p :'
  • 拡張正規表現を試すがどうしてもMacとGit for Windowsはダメ
  • Git for Windowsは{0,1}が使える。基本的にこれで用は足りる
  • 特にMacは標準の正規表現の¥{0,1¥}すら使えない。edもex,viも
  • 唯一WSLだけが正しく機能するので使い分けることにする
  • wslはGitHubにつながらない。引き続き調査が必要