edを使ってみる

1. はじめに
2. 簡単な実例
3. 行の移動について
4. テキスト入力について
5. 小技…置換と検索
6. その他の小技
7. 簡単な実例2
8. おわりに

1. はじめに

edをご存知ですか?などと言うとなにかのCMを思い出す人もいらっしゃるかと思いますが、もちろん、ここで言うedは、Unixにおけるエディタのedのことです。私は、Linuxしか知らないので厳密には、Linuxのedってことになりますが、他のUnix互換OSでもさほど違いはないはず…?

さて、edとはどんなエディタかと言うとエディタとして一番軽いということとラインエディタであることの二つが大きな特徴でしょう。一番軽いということは、つまり、edはどんな環境下でも使え、edが使えない状況下ではもはやなにもできないということです。rescue diskなどでの作業には必須とも言えます。

そんなedですが、今、我々がエディタとして思い浮かべるエディタとはちょっと様子が異なります。我々がエディタと聞いて、まず、思い浮かべるのは、viやemacsのようなスクリーンエディタでしょうが、edはラインエディタなのです。ラインエディタって何?と思う人も多いでしょう。私も最初そう思いました。manなどで調べてみてもコマンドの説明は載っていても、実際の編集ではどうすればいいのかまではよくわかりません。web上にも、その使い方にふれたものはあまりないようです。というわけで、およばずながら私がその実際の使い方の一例を紹介してみたいと思います。


2.簡単な実例

edはラインエディタです。ラインエディタとは、辞書的な言い方をすれば、『行指向のエディタ』とでもなるのでしょうか。『行単位の編集』と説明されることもあります。しかし、やっぱりこれでは、よくわかりません。とりあえず、「edは編集したい行に移動し、その行のみを編集することができる。全体を編集するときは、それを繰り返す」とでも考えてください。まずは、実際の編集の実例をとおして説明していきたいと思います。以下が編集するファイルだとします。
 
/dev/hda1               /                       ext2    defaults        1 1
/dev/hda5               /home                   ext2    defaults        1 2
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
/dev/hda6               swap                    swap    defaults        0 0
/dev/fd0                /mnt/floppy             ext2    noauto,owner    0 0

これに、

/dev/sda1                /mnt/mo                ext2    noauto,owner    0 0

この行をくわえてみることにします。このファイルは、/etc/fstabです。まず、edを起動します。

ed -p @ /etc/fstab
380
@

最初に表示される数字は、このファイルの総文字数です。"-p @"は、なくても問題ありませんが、わかりにくくなるのでつけたほうがいいでしょう。これをつけるとコマンド入力を求められているときは、@が表示されます。ここでは、@を使っていますが、自分の好きなものが使えます。たとえば、ed -p 'ed>'で起動するとコマンド入力を求められているときは、ed>が表示されます。

上記のようにedを起動すると、まずコマンド入力を求められることになります。一般にこの状態をコマンドモードとか編集モードと言うようです。とりあえず、今、自分がどんなファイルを編集しようとしているのかを見てみることにしましょう。

@,p
/dev/hda1               /                       ext2    defaults        1 1
/dev/hda5               /home                   ext2    defaults        1 2
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
/dev/hda6               swap                    swap    defaults        0 0
/dev/fd0                /mnt/floppy             ext2    noauto,owner    0 0
@

","は、このファイルの全ての行を意味し、pはprint、表示せよという意味で、つまり",p"は、すべての行を表示することになります。

edはラインエディタでスクリーンエディタとの最大の違いはカーソルおよびテキストが直接的には見えないことです。ですので、edでは、常に自分がどこを編集しようとしているのかを意識する必要があります。edにおいて位置の単位は行です。つまり常に自分は、今、何行目にいるのかを意識する必要があります。この現在自分のいる行を現在行と呼ぶことにします。また、原則的に編集の単位も行単位で、行中の一部を書き換えたい場合でも、その行全部を書きなおすことになります。

さて、",p"で全体が見えたところで、次は自分が今いる行を特定してみます。

@.
/dev/fd0                /mnt/floppy             ext2    noauto,owner    0 0
@

"."は、今、自分がいる行を意味します。"."だけの時は".p"と同じです。行そのものではなく、行番号を知りたいときも多々あるでしょう。その場合は、

@.=
5
@

とします。"."自分のいる行は"="何行目?といった感じでしょうか。これにより、今、自分が5行目、つまり最終行にいることがわかります。原則的にコマンドを実行したときは、そのコマンドが効力を及ぼした最終行へと移動します。一番最初に、",p"で全行を出力したので最終行に移動したというわけです。ということで、今、5行目、最終行にいることがわかりました。次に、懸案の

/dev/sda1                /mnt/mo                ext2    noauto,owner    0 0

を書き加えてみましょう。あまり意味はありませんが、この行を/dev/cdromの行、3行目の後に付け加えることにします。一旦、3行目に移動します。

@3
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
@

単純ですね。この場合、その行の内容も出力されます。5行目にいたので、-2を指定しても同様の結果になります。次にテキストを入力します。

@a
                #この行の先頭、@の真下にターミナルのカーソルが表示されるはずです。ここから入力します。

コマンド"a"を打つことでテキスト入力モードに移ります。aはadd、付け加える、です。これから入力する行(複数行も可)は、今、自分のいる3行目の後、つまり3行目と4行目の間に挿入されます。

@a
/dev/sda1                /mnt/mo                ext2    noauto,owner    0 0
.                #テキスト入力終了
@

問題の行を書いて、終ったら改行して、"."のみを打って改行です。"."のみの行ができるとedは入力が終了したと認識し入力モードは終了し、再びコマンドモードにもどります。一応、ファイルの中身がどうなったか確認してみましょう。

@,p
/dev/hda1               /                       ext2    defaults        1 1
/dev/hda5               /home                   ext2    defaults        1 2
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
/dev/sda1                /mnt/mo                ext2    noauto,owner    0 0
/dev/hda6               swap                    swap    defaults        0 0
/dev/fd0                /mnt/floppy             ext2    noauto,owner    0 0
@

ちゃんと書き加えられたようです。最後にこれをセーブします。セーブのコマンドは、"w"です。

@w
456
@

表示される数字は、セーブされたファイルの総文字数です。edを終了するコマンドは、"q"です。

@q

なお、コマンドではありませんが、不適切なコマンドを指示すると、edは?を出力します。

@xx
?
@

?が出力されたときは、そのコマンドは間違ったもしくは不適切なコマンドだということです。たとえば"q"を指示したのに?が出力されるときは、まだ、修正されたバッファがファイルに書き込まれず残っているということです。この場合は、"w"でファイルにセーブしてそれから"q"を実行するか、"Q"でバッファを破棄して終了します。


edによる編集作業の大まかな流れはこんなところですが、いろいろと疑問を持った人も多いはずです。行の移動の仕方、編集の仕方、検索、変換などの小技はどうなのかとか…。次にそれらについてふれたいと思います。


3.行の移動について

ed起動直後の現在行は、最終行になります。

行の移動は単純です。直接、数字のみを打つとその数字の行番号の行に移動します。存在しない行番号を打つと、?が返って来て何も起こりません。

@9
9行目の内容が出力される。
@+3
12行目の内容が出力される。
@-3
9行目の内容が出力される。
@.=
9
@

+/-は、単純に現在行から指定した数字の分だけ行を移動します。数字を指定しない時は、+1,-1と同じです。
また、前述したようにコマンドを実行したときは、そのコマンドが効力をおよぼした最終行へと移動します。たとえば、

@5,8p
5行目
6行目
7行目
8行目
@.=
8
@

この場合、5行目から8行目まで出力せよというコマンドを実行しているのですが、コマンド実行後の現在行は、8行目になっています。とくに難しくはありませんが、この挙動は、テキストの出力だけでなく、検索や置換を実行したときも同様です。自分の現在位置を見失わないようにしましょう。

","は、単独で使うとすべての行を意味しますが、行番号を意味する数字ではさむと、n,N(n<Nの必要あり)は、n行目からN行目の間のすべての行を意味します。"."は現在行なので

@.=                 #現在行は何行目か?
15                  #15行目
@.,+3p              #.現在行から+3行目までを出力せよ。
コマンド実行前の現在行 15
+1行目 16
+2行目 17
+3行目 18
@.=                 #現在行は何行目か?
18                  #18行目
@

となります。もちろん","は、-3,+5や-3,.などの使い方もできます。"."は現在行を意味しますが、ほかにもよく使う記号として"$"は最終行を意味します。ですので、現在行から最終行までを出力したいときは、

@.,$p
コマンド実行前の現在行
        |
        略
        |
最終行
@

となります。この時点での現在行はもちろん最終行です。たんに最終行に移動したいときは、"$"単独で使えば簡単です。

@$
最終行
@

行の移動についてはこんなところです。とりあえず、ここでこれまで出て来たコマンドをおさらいしたいと思います。これらのコマンドは、ここでの説明の場合"@"の後に入力します。また、edの原則として行を指定しないときは現在行にそのコマンドを適用します。ただし、行番号を表示する"="は、現在行を表示させる場合にも"."は省略不可のようで、".="とする必要があるようです。

数字
その数字の行番号を意味する。
+
+Nで現在行から+N番目の行を意味する。+単独で使うと+1と同意。
-
-Nで現在行から-N番目の行を意味する。-単独で使うと-1と同意。
,
単独で使ったときは、全ての行を意味する。行番号を意味する数字ではさんだ場合は、その行番号の間のすべての行を意味する。n,Nはただし、実際の行番号になおしたとき、n<Nを満たす必要あり。
.
現在行(行番号)を意味する。また、テキスト入力モードのときは、.単独の行が現れるとテキスト入力モードが終了する。
$
最終行を意味する。
=
行番号を表示する。
p
指定された行を出力する。
a
現在行の後に、テキストを挿入する。
w
ファイルに書き込む。w fileとするとfileに書き込む。単独で使われると、もとのファイルに上書きする。
q
edを終了する。qで?が出力されるときは、バッファをファイルに書き込んでからqを実行するか、Qでバッファを破棄して終了させる。


4.テキスト入力について

ここまでの説明では、現在行の後に挿入する"a"のみを取り上げましたが、実際の編集作業では、これだけではエディタとして使いものになりません。なぜなら、"a"だけでは、行を増やすことはできても減らすことができないからです。このままではファイルの修正もままなりません。編集には行の削除が必須です。行の削除は"d"で行います。

@d
@

これで、現在行が削除されます。ちなみに

@3d
@

とすると、3行目が削除されます。

@+3d
@

この場合は、現在行から+3行目が削除されます。

@7,12d
@

これは当然、7行目から12行目が削除されます。

さて、現在行の移動についてですが、これも原則通り、コマンドの効力が及んだ最終行となります。つまり削除した最終行の次の行が新しい現在位置になります。ただし、次の行があればの話です。次の行がないという場合は、可能な最後の行になります。

これで、エディタとして最低限の機能を使えるようになりました。面倒を厭わなければ、これまででてきたコマンドだけでファイルの編集、修正が可能です。この他に、検索と置換をおぼえれば、実際の使用には十分だと思われます。とは言え、知っておいた方がいいコマンドもあるので、"a"以外のテキスト入力に移行するコマンドについてもふれたいと思います。ここでは、"i"と"c"について紹介します。

これまでにでてきた"a"は、現在行の後ろに新しい行(複数行も可)を挿入するものでした。"i"は現在行の前に行を挿入します。ただ、それだけの違いです。aのaddに対して、iはinsertのことでしょう。"a"と"i"に関しては、どちらかを忘れてしまっても行の移動で十分対応できます。

@,p                           #全体を見てみる
sakura    192.168.45.3
nadesico  192.168.45.4
himawari  192.168.45.5
@.                            #現在行を確認
himawari  192.168.45.5
@i                            #テキスト入力モード開始
sumire    192.168.45.6        #テキスト入力
.                             #テキスト入力終了
@,p                           #編集後の確認
sakura    192.168.45.3
nadesico  192.168.45.4
sumire    192.168.45.6        #テキスト入力モード開始時点の現在行の前に挿入されている
himawari  192.168.45.5        #テキスト入力モード開始時点の現在行
@


次に"c"です。cはおそらくchangeのことでしょう。"c"は、指定した行を削除してそこに新たな行(複数行も可)を挿入します。

@,p                           #全体を見てみる
sakura    192.168.45.3
nadesico  192.168.45.4
sumire    192.168.45.6
himawari  192.168.45.5
@3,4c                         #3行目から4行目を削除して新たな行と入れ替える
tampopo   192.168.45.7        #
mimoza    192.168.45.8        #テキスト入力
azami     192.168.45.99       #
.                             #テキスト入力終了
@,p                           #編集後の確認
sakura    192.168.45.3
nadesico  192.168.45.4
tampopo   192.168.45.7
mimoza    192.168.45.8
azami     192.168.45.99
@

現実の編集作業では、"c"はあまり使うことがありません。なぜなら、行の一部を修正するのに"c"を使うと行をまるごと書きなおす必要があり、やや面倒だからです。それよりも後で説明する置換を使って目的の一部分を修正(というか置換)する方が、手間がはぶけます。なにより、その方が間違いをおかす危険が減ります。edを実際使ってみるとわかると思いますが、edのテキスト入力では間違った部分に戻ってそこだけ修正するということができません。edのテキスト入力では間違ったところまで戻って(削除して)やりなおすしかないのです。テキスト入力はできるだけ避ける方が無難です。

また、edを使わねばならないという場面では大幅なファイルの修正を必要とすることはあまりありません。もし、大幅なファイルの修正を必要とするならば、edで編集するよりも他のマシンでつくったファイルをもってきてコピーしてしまう方が現実的でしょう。

以下、編集に関して取り上げたコマンドをまとめてみました。

d
指定された行を削除する。
a
指定された行の後ろに行を挿入する。
i
指定された行の前に行を挿入する。
c
指定された行を削除し、そこに行を挿入する。


5.小技…置換と検索

ここまでの説明だけでも、edを使うことは可能ですが、使いやすさを考えると不十分です。もっとも、edは限定された環境で使うものなので、使いやすさと言ってもさほど使いやすくなるわけではありませんが…。

まずは、置換です。置換は、s/old/new/で、既存のoldをnewに置き換えます。sはswitchでしょうか。

@.
azami     192.168.45.99
@s/99/199/
@.
azami     192.168.45.199
@

この置換は、行単位で一番最初に一致した文字列のみを置換します。もし、一致する文字列すべてを変換したいときは、gオプションを付加します。gはglobalでしょうか。

@.
松島や、あー松島や、松島や
@s/松島/山寺/g               #gオプションを使って置換
@.
山寺や、あー山寺や、山寺や   #松島がすべて山寺に置換された
@s/山寺/松島/                #gオプションを使わない、デフォルトの動作
@.
松島や、あー山寺や、山寺や   #最初の山寺しか置換されない
@

当然、このコマンドも行を指定して実行することができます。

@,p
sakura    192.168.45.3
nadesico  192.168.45.4
tampopo   192.168.45.7
mimoza    192.168.45.8
azami     192.168.45.99
@,s/9/3/g                #gを指定しないと行単位で最初に一致する文字列ひとつしか置換されない
@,p
sakura    132.168.45.3
nadesico  132.168.45.4
tampopo   132.168.45.7
mimoza    132.168.45.8
azami     132.168.45.33  #gを指定していないときは99は置換されない。
@

結構便利そうに思えますが、複数行に対して置換を実行するような複雑な処理をedでやるのは危険です。edが必要とされるような場面は非常事態でしょうし、edでは、テキスト全体が見にくいので修正も簡単にはいかない場合があります。こういうときは、許すかぎり他のマシンで編集したファイルをもってきて上書きしてやる方がいいでしょう。置換は、"c"のかわりに使うぐらいにとどめておくほうが無難だと思います。

"c"を使って、ownerをuserに書き換える。

@.
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
@c
/dev/cdrom              /mnt/cdrom              iso9660 noauto,user,ro 0 0     #テキスト入力する
.                                                                              #テキスト入力終了
@.
/dev/cdrom              /mnt/cdrom              iso9660 noauto,user,ro 0 0

"c"を使って書き換えると一行まるごと入力する必要があります。つまり、修正の必要のない部分まで新たに書きなおす必要があるのです。

置換でownerをuserに書き換える。

@.
/dev/cdrom              /mnt/cdrom              iso9660 noauto,owner,ro 0 0
@s/owner/user/
@.
/dev/cdrom              /mnt/cdrom              iso9660 noauto,user,ro 0 0
@

置換だと、s/owner/user/ですみますし、修正を必要としない部分を書きなおす無駄と危険をはぶくことができます。


次に、検索です。現在行から後方に検索するときは、"/文字列"とします。現在行から前方へ検索をかけるときは"?文字列"とします。ただ、"/文字列"も"?文字列"も最終行、開始行で検索を折り返してくれるので、検索する文字列がファイル内にひとつしかないときはどちらでもかわりません。また、続けて同じ文字列の検索をかけるときは、それぞれ/、?とします。ただ、この検索は最終行、開始行で折り返してくれるので、漠然と繰り返していると無限に繰り返すことになりますので気をつけましょう。manには、"/文字列/"、"?文字列?"と書かれているかもしれませんが、"/文字列"、"?文字列"も使えるようです。ここではより単純な方を使うことにします。

,pで全体が把握できるような場面では、検索は無意味なのですが、わかりやすさのため

@,p
sakura    192.168.45.3
nadesico  192.168.45.4
tampopo   192.168.45.7
mimoza    192.168.45.8
azami     192.168.45.99
@?5.8                               #最終行から前方に5.8を探す
mimoza    192.168.45.8              #見つかった
@?am                                #次に、ここから前方にamを探す
tampopo   192.168.45.7              #見つかった
@?                                  #再び、ここから前方にamを探す
azami     192.168.45.99             #開始行にまで行った検索は、最終行から現在行へと検索をかける
@

こんな感じです。これを読んだだけではわかりにくいかもしれませんが、実際やってみればそうでもないと思います。

s/old/new/
最初に一致したoldをnewに置換する。すべてのoldをnewに置換するには、s/old/new/gとする。
/文字列
/文字列/
現在行から後方へ文字列を検索する。/(//)とすると再検索する。最終行へたどりつくと開始行から現在行へと検索を続ける。
?文字列
?文字列?
現在行から前方へ文字列を検索する。?(??)とすると再検索する。開始行へたどりつくと最終行から現在行へと検索を続ける。


6.その他の小技

これまでのコマンドを使いこなせれば、実際の場面で困ることはそうないと思います。以下は、知らなくてもかまわないが、知っていると便利なものを取り上げます。

"u"は最後に実行したバッファ変更に対するコマンドを取り消します。

@.
query-source address * port 53;
@s/que/#que/                         #置換で書き換える
@.                                   #どうなったか確認
#query-source address * port 53;     # #が追加されている
@u                                   #前回のコマンドを取り消し
@.                                   #どうなったか確認
query-source address * port 53;      #もとに戻っている。
@

"Q"は、バッファを破棄してedを終了します。当然と言えば当然ですが、いったんwで書き込んだら、"u"でも取り消せないし、"Q"でも破棄できませんのでwは慎重に実行しましょう。

最後は、"!"です。!commandとするとシェルコマンドcommandを実行することができます。比較的便利なのは、ヴューワーの実行でしょう。edでは、テキスト全体を把握するのはなかなか大変です。ですので、全体の把握に、lessなどを使えれば便利です。もっとも、edが必要な状況ではlessさえ動かなかったりするのですが…。

現在、/etc/ntp.confを編集中だとして

@!less /etc/ntp.conf
#
# Drift file.  Put this in a directory which the daemon can write to.
# No symbolic links allowed, either, since the daemon updates the file
# by creating a temporary in the same directory and then rename()'ing
# it to the file.
#
driftfile /etc/ntp/drift

lessの画面〜以下略〜
@

この場合、lessを終了させると、edのコマンドモードに戻ります。"!"は、別に現在実行中のedに関係のないコマンドでも実行可能です。たんにedがバックグランドにいくだけだと考えてもよさそうです。

ほかにも、"r"や"W"など、編集中のファイルと他のファイルを結合するコマンドなどがあるのですが、これら複雑な処理はedでやらなくてもいいような気がしますので、ここでは取り上げません。

u
最後に実行したバッファ変更のコマンドを取り消す。
Q
バッファを破棄してedを終了する。
!command
シェルコマンドcommandを実行する。


7.簡単な実例2

一通り説明の終ったところで、実際の編集の一例を紹介します。このサーバーのホストネーム(コマンドhostnameが返す名前)は、非公式なドメインのazamiです。apacheはデフォルトでは、サーバー名はこのホストネームを使います。しかし、このサーバーは、www.karing.jpとして公開されています。最終的にはIPアドレスで解決されるので実用上さほど問題がないと言えばないのですが、グローバルには存在しないURLが外部に出てしまうのは気持ちのいいものではないので、apache(httpd)にはちゃんと自分がwww.karing.jpであることを教えておきます。

ed -p @ /etc/httpd/conf/httpd.conf         #edを起動
41563

41563とはさすがに大きなファイルです。これぐらい大きなファイルになると,pで全行出力して全体を把握するのはちょっと大変です。というわけで、lessでhttpd.confの中身を見てみます。

@!less /etc/httpd/conf/httpd.conf
##
## httpd.conf -- Apache HTTP server configuration file
##



# this, ask your network administrator.
# If your host doesn't have a registered DNS name, enter its IP address here.
# You will have to access it by its address (e.g., http://123.45.67.89/)
# anyway, and this will make redirections work in a sensible way.
#
#ServerName localhost

#
# DocumentRoot: The directory out of which you will serve your

以下略

どうやら、#ServerName localhostの行をコメントアウトし、localhostの部分を書きなおせばよさそうです。lessを終了し、ServerName localhostがある行を探します。

@1                #とりあえず、わかりやすく1行目にもどってみます
##
@

目的の場所をさがして検索をかけます。

@/ServerNa
# ServerName: allows you to set a host name which is sent back to clients for
@

残念、ここではないようです。次の候補を探します。

@/
#ServerName localhost
@

見つかりました。何行目かを調べます。

@.=
402
@

402行目だそうです。このファイルに他に同じようなところがないか念のために調べます。

@/
# to the server the response is coming from) it will use ServerName and
@/
#    ServerName host.some_domain.com
@/
# ServerName: allows you to set a host name which is sent back to clients for
@/
#ServerName localhost
@.=
402
@

一周まわってみて、どうやら書き換えるのは#ServerName localhostの行でよさそうですが、ServerName host.some_domain.comの行も気になるので、再びlessで調べてみます。

@!less /etc/httpd/conf/httpd.conf

@

見てみると、どうやらServerName host.some_domain.comの行はヴァーチャルホストの設定のようです。ということで、今回書き換えるべき行は、#ServerName localhostで間違いないでしょう。

@.                         #現在行を一応確認
#ServerName localhost
@c                         #短いので、"c"で書き換え
ServerName www.karing.jp
.                          #テキスト入力終了
@.                         #一応確認
ServerName www.karing.jp   #だいじょうぶのようだ
@w                         #セーブ
41566
@q                         #edを終了

"w"でセーブしないとファイルに反映されないので忘れずにセーブしてください。おおまかな感じはこんなところです。文字にするとなにか難しく感じますが、実際は単調、単純な作業です。


8.おわりに

たぶん、これまで出てきたコマンドだけで十分にedを使いこなせると思うのですが、edにはここで取り上げていないコマンドももちろんあります。また、同じ動作をする異なる文字(コマンド)もあります(例、"^"と"-")。興味のある人は、manなりinfoなりを参照してください。また、検索では簡単な正規表現も使えますが、必要であれば、これについてもそれらの専門文書にあたってみてください。まぁ、edはある意味非常事態のためのものなので、そんなエキスパートにならなくとも…、と思いますが、ただ、少しは日頃から慣れておかないといざというときに困るので、困らない程度に日頃から慣れておくことをおすすめします。

最後になってしまいましたが、ここまで取り上げてきたedの使い方は、私の個人的なくせ、習慣とも言えるものなので、必ずしも正解ではないかもしれません。使いやすさの感覚は人それぞれですし、自分は別なやり方の方がやりやすいと思ったら、ここで紹介したことに縛られる必要はまったくありません。やりやすいようにやってください。

とりあえず、これで終りです。さて、どうだったでしょうか?なにか間違っているところとか、わかりにくいところとかなかったでしょうか?ほかにも、こうすればいいとか、こうすべきとか…、このHOWTOをよりよきものにするために、よろしければ、ご意見ご感想などお聞かせ下さい。


2002年9月15日 よしのぶ
yoshino@rita.karing.jp

index.html  飛べ!ペンギン大王