ed は Unix 標準のラインエディタです。ラインエディタなので編集は行単位になります。スクリーンエディタに慣れた現代では過去のアプリケーションと思われていますし、実際、ed を使ってファイルの編集をする人はいないでしょう。しかし、ed を学習する理由は十分にあります。
それは、ed の編集が正規表現を利用して行われるからです。正規表現は Unix ではあらゆるところで活用されています。grep, sed, awk, less, vi, などあらゆるコマンドで正規表現は活躍します。したがって、ed を使えるようになることは、正規表現に習熟し、Unix を駆使できるようになることと同じなのです。
幸い ed の仕様はそう大きなものではないので学習は楽です。簡単なプログラムなら ed で作成したほうが楽だと思えるようになると思います。
ed の目的は文書を作成し、保存することです。ed は他のエディタと同様に入力した文書は一旦メモリのバッファに書き込まれます。バッファの文書は ed を終了すると破棄されるので、その前にファイルへの保存が必要です。
したがって、ed のもっとも基本的な操作は ed の起動、文書の作成、ファイルへの保存、ed の終了という流れになります。
まず、起動と終了をやってみましょう。ed を起動するにはコマンドラインから ed と入力します。起動したらそのまま q だけを入力して、リターンキーを押すと終了します。q は quit (終了) の意味です。
~/markdown/simple$ ed
q
~/markdown/simple$
起動して終了するだけならつまらないので、文書を入力してみます。ed で文書を編集するときに注意する必要があるのは、コマンドモードと入力モードがあることです。編集のコマンドを入力するモードと、実際に文字列をバッファに書き込むモードです。vi でおなじみの入力方法です。
典型的なコマンドは次のような形式をとります。
,s/OLD/NEW/g
このコマンドを実行するとすべての行の OLD という文字列が NEW という文字列に置換されます。
ed の起動直後はコマンドモードになっています。コマンドモードから入力モードになるには a (append), i (insert), c (change) モードのいずれかの入力用コマンドを入力します。一般には a を使います。入力モードでは普通に複数の行を入力していくことができますが、入力中にコマンドを実行することはできません。入力が終わってコマンドモードに戻るには . (ドット) のみを入力します。
入力した文書はバッファに保存されているだけなのでこれをファイルに書き出します。w (write) コマンドはバッファの文書をファイルに保存するコマンドです。w ファイル名 という使い方をします。保存ができたら q (quit) コマンドで ed を終了してもファイルに文書が保存されています。
~/markdown/simple$ ed
a
#! /bin/bash
echo "hello, world"
echo "how are you?"
.
w foo
53
q
~/markdown/simple$ cat foo
#! /bin/bash
echo "hello, world"
echo "how are you?"
作成した文書は、コマンドラインから ed ファイル名 で読み込むことができます。読み込んだ文書は ,p コマンドで確認できます。
~/markdown/simple$ ed foo
53
,p
#! /bin/bash
echo "hello, world"
echo "how are you?"
p (print) コマンドで文書を表示するときは、表示する行を指定できます。
2p
echo "hello, world"
また、行の範囲を指定して表示することもできます。
1,3p
#! /bin/bash
echo "hello, world"
echo "how are you?"
$
記号は行末を表します。位置を表す記号には現在の行を表す .
もあります。行は数字やこれらの記号を混在して表すことができます。
2,$p
echo "hello, world"
echo "how are you?"
p コマンドの代わりに n コマンドを使うと、行番号を表示させることができます。
,n
1 #! /bin/bash
2 echo "hello, world"
3 echo "how are you?"
数字だけを入力すると、指定した行をカレント行にできます。後で述べるようにコマンドによる行の編集はカレント行に対して行われます。
3
echo "hello, world"
ed はラインエディタです。したがって、編集は行単位で行われます。行の内容を変更したいときは行番号を指定して、編集コマンドの a, i, c のいずれかで行を入力します。1行の一部を変更したいときも1行すべてを新しく入力します。実はもっとうまい方法があるのですがここでは基本的な入力方法を説明します。
行の編集はカレント行に対して行われます。行の番号を入力するとその行がカレント行になり、編集を行うことができます。
2
echo "hello, world"
a コマンドを使うと、カレント行の次に行を追加できます。
a
echo "appended line"
.
,p
#! /bin/bash
echo "hello, world"
echo "appended line"
echo "how are you?"
i コマンドを使うとカレント行の上に行を追加できます。
2
echo "hello, world"
i
echo "inserted line"
.
,p
#! /bin/bash
echo "inserted line"
echo "hello, world"
echo "appended line"
echo "how are you?"
c コマンドを使うとカレント行を入力した行で置き換えることができます。
3
echo "hello, world"
c
echo "changed line"
.
,p
#! /bin/bash
echo "inserted line"
echo "changed line"
echo "appended line"
echo "how are you?"
d コマンドは行を削除します。
3
echo "changed line"
d
,p
#! /bin/bash
echo "inserted line"
echo "appended line"
echo "how are you?"
指定した範囲の行を削除することもできます。
2,3d
,p
#! /bin/bash
echo "how are you?"
これらの編集の結果はバッファに書き込まれていますが、ファイルには保存されていません。編集を破棄して終了するには Q コマンドを使います。
Q
~/markdown/simple$ cat foo
#! /bin/bash
echo "hello, world"
echo "how are you?"
編集の作業では今行った編集を取り消したいときがよくあります。ed では直前の作業だけですが u コマンドを使うと取り消すことができます。
~/markdown/simple$ ed foo
53
,p
#! /bin/bash
echo "hello, world"
echo "how are you?"
2d
,p
#! /bin/bash
echo "how are you?"
u
,p
#! /bin/bash
echo "hello, world"
echo "how are you?"
編集コマンドは、指定行(カレント行)または、指定範囲の行(アドレス)に対して行います。Ed の 編集コマンドは、(カレント行/アドレス)コマンド(パラメータ)の順に記述します。例えば、2i や 1,2d の様に入力します。コマンドがカレント行に適用されるときは省略され、i や s/hello/hi/ などのような使い方をします。
カレント行の指定は行番号を入力するだけです。
~/markdown/simple$ cat foo
#! /bin/bash
echo "hello, world"
echo "how are you"
echo "nice to meet you"
~/markdown/simple$ ed foo
76
2
echo "hello, world"
行番号を直接入力する以外にも // コマンドで正規表現検索をすることもできます。
/nice
echo "nice to meet you"
範囲指定(アドレス)は範囲の最初の番号と最後の番号をコンマで区切って指定します。次の例ではアドレスの後に p (print) コマンドを適用して、指定範囲の行の表示をしています。
2,4p
echo "hello, world"
echo "how are you"
echo "nice to meet you"
範囲指定は、正規表現検索で行うこともできます。
/bash/,/hello/p
#! /bin/bash
echo "hello, world"
ed で最も使われるのが置換コマンド s です。行単位の編集だと、行の変更に行を全部入力しないといけませんが、s コマンドを使うと行の一部だけを検索して置き換えることができます。例えば次の文書 foo の2行目の world を there に変更するには次のようにします。
~/markdown/simple$ ed foo
76
,p
#! /bin/bash
echo "hello, world"
echo "how are you"
echo "nice to meet you"
2
echo "hello, world"
s/world/there/
,p
,p
#! /bin/bash
echo "hello, there"
echo "how are you"
echo "nice to meet you"
s コマンドの後にスラッシュ記号で囲まれた、検索文字 world をその後のスラッシュで囲まれた there に置換します。検索文字は普通の文字列も使えますが、正規表現を使うと文字列のパターンにマッチさせることができます。正規表現については、後述します。
また、置換文字に何も指定しないと、s/there// のようになりますが、この場合は there を削除することになります。
2
echo "hello, there"
s/there//
p
echo "hello, "
行の範囲指定を行うと、その範囲の行すべてに s コマンドを適用できます。
2,4s/echo/printf/
,p
#! /bin/bash
printf "hello, world"
printf "how are you"
printf "nice to meet you"
Perl や Ruby で多用される正規表現ですが、元々は ed で使われ始めました。正規表現ではメタ文字を使うことで文字列だけでなく、文字列のパターンで検索することができます。メタ文字は文字そのものではなくパターンを表現するために用いられます。メタ文字そのものを入力したいときは \* の様にエスケープ文字にします。ed で利用できるメタ文字には次のようなものがあります。
ブラケットで文字列を囲むと、それはその中の文字列のどれか一つにマッチするパターンになります。例えば [eo] は文字 e かまたは文字 o のいずれかにマッチします。したがって、h[eo] は he にも ho にもマッチします。
~/markdown/simple$ ed foo
76
,p
#! /bin/bash
echo "hello, world"
echo "how are you"
echo "nice to meet you"
/h[eo]
echo "hello, world"
/h[eo]
echo "how are you"
検索のときに g プレフィクスを使うと、すべての検索結果を表示できます。
g/h[eo]
echo "hello, world"
echo "how are you"
echo "nice to meet you"
ブラケットの先頭に ^ があると、ブラケット内の文字列以外の文字にマッチします。h[^o] は h の次に o ではない文字が続くパターンにマッチします。
/h[^o]
echo "hello, world"
ワイルドカード . はすべての1文字にマッチします。" ... " は前後がスペースの3文字のパターンにマッチします。
/ ... /
echo "how are you"
メタキャラクタの ^ は文字列の先頭にマッチします。また、$ は文字列の末尾にマッチします。
g/^echo
echo "hello, world"
echo "how are you"
echo "nice to meet you"
g/you"$
echo "how are you"
echo "nice to meet you"
メタキャラクタ * は直前の1文字の0回以上の繰り返しにマッチします。
g/l[l]*/ echo "hello, world"
パターンを括弧 ( ) で括ることによってそれを一つのパターンとみなすことができます。例えば、
'\(a.c\)\1'
というパターンは a.c というパターンを2回繰り返したものになります。これは abcabc にはマッチしますが abcadc にはマッチしません。間の b と d が異なっているからです。
上の ( と ) がエスケープされているのは ( ではなく \( 、) ではなく \) がメタ文字だからです。メタ文字には他に以下のようなものがあります。詳しくは info ed で参照できます。
'\{N\}'
直前の文字がN以上M以下出現するパターン
'\>'
単語の前後を表すアンカー
'\''
行頭、行末を表すアンカー
'\?'
直前の文字0文字または1文字とマッチ
'\+'
直前の文字の1以上の繰り返しにマッチ`\b'
単語の前後をあらわすアンカー
'\B'
単語全体にマッチするアンカー
'\w'
単語の中の任意の1文字にマッチ
'\W'
単語に含まれない任意の1文字にマッチ
正規表現は文字列の検索が主な目的です。しかし、s コマンドに利用することで検索した文字列を別の文字列に置き換えることができます。ed による文書の編集は主にこの s コマンドと正規表現で行います。s コマンドの文法は次のようになります。
'(.,.)s /RE/REPLACEMENT/'
カレント行、または指定範囲の行の、正規表現 RE にマッチする文字列を REPLACEMENT で置き換える。
'(.,.)s /RE/REPLACEMENT/g'
カレント行または指定範囲の行の、正規表現 RE にマッチするすべての文字列を REPLACEMENT で置き換える。
'(.,.)s /RE/REPLACEMENT/N'
カレント行または指定範囲の行の、正規表現 RE にマッチスする文字列のうち N 番目に出現したものを REPLACEMENT で置き換える。
正規表現のうちサブエクスプレッションにマッチしたものは、REPLACEMENT で \N で置き換えることができます。
Ed の編集の中心が正規表現の使い方にありますが、man ed や info ed の記述も十分ではありません。また、ed があまり使われないツールのためかネットの記事も少ないようです。他の言語の正規表現の教科書も参照しながら手探りで見つけていくことになるのでしょう。しかし、それを置いても十分楽しめるツールです。
ed エディタでは、正規表現を使った s コマンドで編集を行うので、自然に正規表現に慣れるようになります。sed よりも対話的に正規表現のパターンを確認できるので、sed や awk の理解が容易になります。また、小さいスクリプトであれば、ed は vi などより反応が速いので便利です。vi とは違って基本的にコマンドラインで実行されるので、文書編集のログを取るのも簡単です。用途によっては ed もまだまだ現役です。
戻る