(非vimmer向け)ラインエディタedを触る


はじめに

初期のUNIXのエディタであり、awk、sed、grep、さらにviのルーツにも位置し、そして「世界初の正規表現の実装のひとつ」らしいラインエディタedを触ってみたのでその記録です。

edの詳しい使い方を見る記事ではありません。(私は全然詳しくないです)
非vimmerな私が、edを通してラインエディタの考え方を確認しながら「viのコマンドと同じだなあ〜」「grepの語源はこれか!」と歴史にふれつつ理解を深めようという趣旨です。
なので、これらのコマンドを多少使ったことがある人や学習を始めた新人さんなどに読んでいただければと思います。

vimmerの方々は「exモード」(「:」でやるやつ)で日々やっているのでしょう。
複数行を素早く処理する姿、かっこいいですよね。

edの基本的な考え方

  • 「いま自分がいる行」の概念があり、アドレスを指定することで移動できる。
  • コマンドによる処理は指定したアドレスに対して施される
  • バッファ内での処理

といったところじゃないでしょうか。
これらの考え方自体は全然レガシーなものでなく、作業効率や安全性から現在でも有用だと思います。

もちろん、1行ずつしか処理できなかったら使いにくいですよね。
複数行をまとめて処理するには、処理対象であるアドレスを

  • 行範囲で指定(例、3,$
  • 正規表現で指定(例、/^#/

と複数指定する、という考え方になります。

実際に触ってみよう

現在の位置の概念があるのでedはコマンドの説明だけ読んでも挙動がわかりにくいです。
下記、一連の流れになってるので、自分がいまどこにいるのかを意識しながら読んでみてください。

では、やってみます。(Mac環境です。)

基本操作(指定したアドレスにコマンドで処理)

このテキストファイルをいじっていきます。

sample.txtの現在の状態
hoge
fuga
piyo
ターミナル
# まずはファイルをバッファに読み込みます。
> $ ed sample.txt
15
# へー、ファイルの文字数が表示されるんですね。
# 私は今どこにいるのでしょうか?
# 現在のアドレスを表示するコマンド=を打ってみましょう
> =
3 
# ・・・ということは、ファイルを開いた直後は最終行にいるんですね。
# 行を表示するコマンドpを打ってみましょう。
> p
piyo
# 自分が今いる行=3行目が表示されましたね
# アドレスはデフォルトでは現在位置になっている、ということです。

# 行番号指定で1行目に移動してみましょう
> 1
hoge
# 移動先の行が表示されましたね
# でも、移動せずに処理もできます。[アドレス][コマンド]の形式で。
> 2p
fuga
# 2行目が表示されました。
> =
1
# 位置は変わってないですね。

# アドレスとして、行の範囲をN,Nの形式で指定してみましょう。
> 1,3p
hoge
fuga
piyo
# 1から3行目が表示されましたね
# 行を削除するコマンドdも使ってみましょう
> 1d
# hogeの行は本当に削除されたかな?
# 最初の行を意味するシンボル^を打って確認してみよう
> ^
fuga
# 削除されてますね。
# 削除しちゃったので戻すためにバッファを破棄して終了するコマンドQを打ちます。
> Q
# ファイルを確認すると・・・
> $ cat sample.txt
hoge
fuga
piyo
# hogeの行は消えてないですね。

正規表現によるアドレス指定、バッファ処理コマンド

sample.txtの現在の状態
hoge
fuga
piyo
ターミナル
# では、再度edします。
> $ ed sample.txt
15
# アドレスを正規表現で指定してみましょう。おなじみ/[パターン]/の形式です。
> /^f/
fuga
# 複数一致するパターンを打つとどうなるでしょうか?
> /o/
piyo
# もう一度打つと・・・
> /o/
hoge
# 次の一致に移動してますね。

# では、複数行まとめて処理してみましょう。
# 正規表現に一致するものすべてに処理を施すグローバルコマンドgを使います。 
# g/[パターン]/[コマンド]の形式です。
> g/o/p
hoge
piyo
# このg/[re]/pの形式がまさにgrepですね!

# 入力モードになり行を追加(append)してみます。aコマンドです。
# $は最終行を表すシンボルです。
> $a 
# 入力モードになっているので、テキストを入力します。
> bar
# コマンドモードに.で戻りましょう
> .
# バッファの編集を確認してみます。
# ,だけで全行指定できます。
> ,p
hoge
fuga
piyo
bar
# 最終行にbarが追加されていますね。

# barの前にfooを挿れてみましょう。
# 入力モードになり行を挿入(insert)します。iコマンドです。
> $i
> foo
hoge
fuga
piyo
foo
bar
# 挿入できてますね。

# バッファをファイルに書き込んで(write)作業を保存しましょう。wコマンドです。
> w
23
# 書き込んだ後のファイルの文字数が出力されました。
# 終了(quit)するにはqコマンドを打ちます。
> q

置換コマンド

sample.txtの現在の状態

hoge
fuga
piyo
foo
bar
ターミナル
# では、最後に、置換(substitute)をしてみましょう
# 再度edします
$ ed sample.txt
> 23
# コマンドsを使って、[アドレス]s/[パターン]/[置換文字列]/の形式で置換します。
# いかにもsedですね
# アドレスに全行を指定して全てのoをxに置換してみましょう。
> ,s/o/x/
hxge
fuga
piyx
fxo
bar
# あれ、fxoになってますね?
# そうです、同じ行でマッチしたパターンすべてに対し置換を行うにはgを付け足します。sedもそうですよね。
# 形式は、[アドレス]s/[パターン]/[置換文字列]/g です。
# まず、uコマンドで直前のコマンドを取り消し(undo)しましょう。
> u
hoge
fuga
piyo
foo
bar
> ,s/o/x/g
hxge
fuga
piyx
fxx
bar
# 意図した結果になりました!
# アドレスに正規表現をつかった置換をして、以上のまとめとしましょう。
> g/^.x.*/s/x/y/g
> ,p
hyge
fuga
piyx
fyy
bar
# 最初のgと最後のgの意味を混同しないようにしてくださいね!

・・・と、edを初めて触ったものの、コマンドや構文はなんか知っている感じがしますね!
grepはedのg/[re]/pですし、sedはedのアドレス全行指定がデフォルトのストリーム版という感じですし、またviでつかうコマンドもバッファの処理に散見され、edがこういうツールのルーツなんだなあと実感できます。

いま思えばedは、私が新人の頃、viやsed、grep、また正規表現などに初めて触れた頃にやっておきたかった思考経済的な学習ツールと言えます。
新人さんの学習にぜひオススメしたいですね。