いますぐ実践! Linuxシステム管理

[バックナンバーのトップへ] [Linux システム管理のトップへ]


いますぐ実践! Linux システム管理 / Vol.196 / 読者数:1750名

こんばんは、うすだです。

先日、生まれて初めて、コイン精米を利用しました。

といっても大層なことは微塵もなく、お金と玄米を入れて、 精米のレベル(上白、標準、8分など)を選んだら、 あとは白米がじゃんじゃか出てくるだけでした。素人のわたし一人でも、 難なくこなすことができました。

さて、コイン精米を利用して気づいたことがあります。
それは、結構な数のスズメが、わりと近くで待機していたことです。

精米を機械に入れて、出てきた白米を袋に入れるまでの間に、 どうしても米が少しはこぼれてしまいます。
その米をスズメがおいしくいただき、 スズメが食べてくれることでコイン精米の周辺がきれいに保たれるという、 Win-Win な関係が成り立っているわけですね。

イソギンチャクとクマノミのような共生関係が、 スズメとヒトとの間にも成立しているとは、予想外でした。

 

…というのはもちろんウソで、ただ単に意外に思っただけです。

しかし、コイン精米にスズメが集まるという事実は、 コイン精米に行ってみないとわからなかったことです。
なにごとも経験してみないといけない、ということを再認識しました。

同様に、下記のお題の中身を読んで、ああわかったわかったと思っても、 実際に実行してみる必要があるのではないでしょうか。
実際、書いてあることはたいしたことありませんので、面倒くさがらず、 ぜひ実行してみてください。

うまいことまとめたところで、今回もはりきってまいりましょう!!

今回のお題 - いまさらだけど正規表現を始めてみる

ひょんなことから、「etckeeper」なるものを知りました。
/etc 以下のファイルを、 git や Mercurial 等のバージョン管理システム経由で管理するツールです。

以前に、似たようなことをとりあげたことがありますので、こいつぁいいと思って、 使いながら調べていたのですが、etckeeper を使うメリットがいまいちわからず、 今回のお題にするのを諦めました。

 

というわけで、ネタがなくなり途方に暮れていたのですが、本来、 Linuxのシステム管理に関するネタなんて、星の数ほどあるはずです。

そして、ふと思ったのです。「正規表現」なのではないかと。

たくさんあるファイルの一部を同じように書き換えたり、 手で書き換えるのではなくコマンド等で書き換える必要があるときなどの際、 正規表現を知っているひとは、なにげなく正規表現を使っていると思います。

ですが、正規表現をいまいちわかっていない方にとっては、 そういうことを気軽にできないんじゃないかと思うのです。

ですので、今回は、正規表現を取り上げたいと思います。
前半は、正規表現のさわりをご紹介し、後半でそれらを使った例を示そうと思います。

正規表現とは

まず、正規表現とはなにか、簡単にご説明します。

正規表現(Regular Expression)とは、 文字列の集合を一つの文字列で表現する方法の一つです。…と、 Wikipedia さまがおっしゃっています。

正規表現 - Wikipedia
http://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE

ようするに、共通点のあるいくつかの文字列を、 正規表現でまとめて表すことができる、ということです。

たとえば、/etc/hosts の中で、 IPアドレスが「192.168」で始まる行だけを抜き出すには、 grep コマンドを使用して以下のように実行します。

  $ grep "^192\.168" /etc/hosts
  192.168.1.1     tamao     # Added by NetworkManager
  192.168.1.101   vine
  192.168.1.102   win2k
  192.168.1.103   ibook
  ...

現在、様々なコマンドやアプリケーション、 言語で正規表現が扱えるようになっています。
それぞれ、使える正規表現が微妙に異なりますが、以降では、 だいたいのコマンドで使える簡単なものを、ご紹介したいと思います。

正規表現のさわり

まず、英数字などは、その文字そのものを表します。

たとえば、「chestnut」という表現は、「chestnut」という文字列だけにマッチします。

もちろん、それだけでは複数の文字列をまとめて表すことができません。
ですので、「メタキャラクタ」と呼ばれる、特別な意味を持つ文字を使うことで、 まとめて表します。

つまり、メタキャラクタをうまく使いこなすことが、 正規表現をマスターするということだと言っても過言ではありません。

というわけで、以降では、だいたいどこでも使えるメタキャラクタの代表的なものを、 簡単にご紹介していきます。

メタ
キャラクタ
説 明
^ 「^」は、文字列の先頭を表します。
たとえば、「^Document」という表現は、先頭が「Document」で始まる文字列を表します。
$ 「$」は、文字列の末尾を表します。
たとえば、「None$」という表現は、末尾が「None」で終わる文字列を表します。
. 「.」は、任意の一文字を表します。
たとえば、「c.t」という表現は、 「c」で始まり「t」で終わる3文字の文字列を含む文字列を表します。
ですので、「cat」や「cut」などが該当します。
ただ、たとえば grep コマンドの引数で指定する場合、 「c.t」を含む文字列すべてが該当します。ですので、 「cats」「category」といった文字列はもちろん、 「allocate」や「black cat」「execute ls」なども該当します。
(以降も同様ですので、以降では上記的な例を割愛します。)
* 「*」は、直前の文字の0回以上の繰り返しを表します。
たとえば、「mar*on」という表現は、「maon」「maron」「marron」…など、 間の「r」が0回以上繰り返される文字列が該当します。
(ですので、「marrrrrrrrrrrrrrrrrrrrrrrrrrrrron」も該当します。)
ちなみに、「+」は、直前の文字の1回以上の繰り返しを表します。
たとえば、先の「*」を「+」に置き換えた「mar+on」だと、 間の「r」が1回以上繰り返される必要があるため、「maon」は該当しません。
[abc] 「[]」でいくつかの文字を囲った場合、 その中の文字のいずれか一文字を表します。
たとえば、上記の「[abc]」は、「a」「b」「c」のいずれかです。
また、「[Aa]poptosis」という表現は、 「Apoptosis」か「apoptosis」のいずれかということになります。
[^abc] 先ほどと似ていますが、「[]」の中の文字の先頭が「^」となっている場合、 それらの文字以外のいずれか一文字を表します。
たとえば、上記の「[^abc]」は、「a」「b」「c」以外の一文字です。
[a-c] 「[]」の中に指定する文字が広範囲の場合、一つ一つ指定するのは大変ですので、 「-」で範囲を指定できます。
たとえば、上記の「[a-c]」という表現は、「[abc]」と同じ意味です。
また、「[0123456789]」という表現は、「[0-9]」と表せます。
\ メタキャラクタそのものを指定したい場合、先頭に「\」をつけます。
たとえば、任意の一文字ではなく「.」そのものを表現したいときは、 「\.」と表現します。
ですので、「192.168.1.1」は「192\.168\.1\.1」と表します。
また、電話番号は、「[0-9]+\-[0-9]+\-[0-9]+」と表せます。

他にもありますが、最初はこのくらい知っておけば十分だと思います。

正規表現を使ってみる

説明を読んでいるだけではつまらないですよね。
それでは、実際に試してみましょう。

本メルマガの過去の記事が、「番号.txt」というファイル名で、 カレントディレクトリにあるとします。
ここでは、それらのファイルから、 sed コマンドを実行している箇所だけを抜き出してみたいと思います。

まずは安直に、「sed」で grep してみましょう。

  $ grep sed *.txt
  019.txt:  Connection closed by foreign host.
  019.txt:  telnet: connect to address 127.0.0.1: Connection refused
  020.txt:  Connection closed by foreign host.
  020.txt:  Connection closed by foreign host.
  ...

…案の定、closed とか refused とか Used とか、 関係ないものが多量に引っかかってしまいました。

ということは、「sed」の前後が英数字でなければよさそうです。
英数字でないというのは、「[^A-Za-z0-9]」と表せますので、 これを前後につけた「[^A-Za-z0-9]sed[^A-Za-z0-9]」で試してみましょう。

  $ grep '[^A-Za-z0-9]sed[^A-Za-z0-9]' *.txt
  072.txt:  > sed -i "s/%%HOSTNAME%%/`hostname`/g" $file
  072.txt:  > sed "s/%%HOSTNAME%%/`hostname`/g" $file > new/$file
  ...
  077.txt:rndc の出力結果を sed に渡しているのは、出力結果の先頭に
  ...
  097.txt:いくつか方法がありそうですが、ここでは sed コマンドを
  ...
  156.txt:  $ sed -e 's/@PACKAGE@/dnotify/;s/@VERSION@/0.18.0/' \
  ...

だいぶよいですが、本文中に出てくる sed も選ばれてしまっています。
それらは、行の先頭が空白文字でないようですので、 先頭がスペースの行に絞ればよさそうです。
先頭がスペースというのは、「^ 」で表せます。 それから sed が現れるまでの間はなんでもよいので、「.*」で表せます。
これらを連結すると、「^ .*[^A-Za-z0-9]sed[^A-Za-z0-9]」という表現になります。 試してみましょう。

  $ grep '^ .*[^A-Za-z0-9]sed[^A-Za-z0-9]' *.txt
  072.txt:  > sed -i "s/%%HOSTNAME%%/`hostname`/g" $file
  072.txt:  > sed "s/%%HOSTNAME%%/`hostname`/g" $file > new/$file
  ...
  156.txt:  $ sed -e 's/@PACKAGE@/dnotify/;s/@VERSION@/0.18.0/' \
  157.txt:          echo $messages | sed 's/@RET@/\n/g' | \
  ...

厳密にはまだ正しくないかもしれませんが、目的は達せられたと言ってもよいと思います。

 

あともう一つ、例を示します。

/etc 直下でない設定ファイル、 つまり /etc/resolv.conf などのようなファイルではなく、 /etc/bind/named.conf や /etc/apache2/httpd.conf など、 間に1つ以上のディレクトリがあるファイルを検索してみます。

やはり、まずは安直に「/etc」で grep してみます。

  $ grep /etc *.txt
  001.txt:たとえば,/home/usu, /var/named, /etc のバックアップを
  001.txt:  # ./backup.sh /home/usu /var/named /etc
  002.txt:ちなみに,root の場合は,/etc/crontab ファイルを直接編集
  ...

…のっけから外しまくっていますね。
ようは、「/etc」の後に「/」が2つ続き、 かつその間に空白以外の文字があればよいと思われます。
ということで、「/etc/[^ ][^ ]*/.」で grep してみましょう。

  $ grep '/etc/[^ ][^ ]*/.' *.txt
  006.txt:ファイルを,/etc/xinetd.d/usoweb として保存してください.
  007.txt:次に,/etc/xinetd.d/meminfo を作成します.内容は以下の通り
  013.txt:xinetd の場合,/etc/xinetd.d/telnet を,以下のようにします.
  ...
  127.txt:/usr/lib/named/etc/bind/named.conf.local に、以下の設定が
  ...

よい感じですが、 「なんとか/etc/なんとか」という文字列まで含まれてしまっています。
それでは、上記に該当するものを除外してしまいましょう。
「-v」オプションをつけて grep を実行すると、 該当しない行を出力するようになります。
ですので、「/[^ ][^ ]*/etc」を grep -v してみましょう。

  $ grep '/etc/[^ ][^ ]*/.' *.txt | grep -v '/[^ ][^ ]*/etc'
  006.txt:ファイルを,/etc/xinetd.d/usoweb として保存してください.
  007.txt:次に,/etc/xinetd.d/meminfo を作成します.内容は以下の通り
  013.txt:xinetd の場合,/etc/xinetd.d/telnet を,以下のようにします.
  ...

出てこなくなりました。目的が達せられたようです。

ちなみに、「/etc/[^ ][^ ]*/.」は「/etc/[^ ]+/.」と表すこともできるのですが、 grep コマンドは「+」を理解してくれませんでしたので、 上記では「+」を使っていません。

おわりに

以上、正規表現のさわりをご紹介しました。

「正規表現」という名の分厚い本があるくらいですので、ご紹介した内容は、 ほんとにさわりです。私自身、昔からテキトーに使っていますので、 どこまで正しく理解しているかわかっていないという有様です。

また、Perl などでは、正規表現を拡張していたりもします。
他で使うときに注意しないといけませんが、かゆいところに手が届くのであれば、 積極的に使ってみてもよいのではないでしょうか。

宿題の答え

前回の宿題は、

  IPv4アドレスもIPv6アドレスもあるホスト名でアクセスすると、どちら
  が優先されるか確認してみましょう。

でした。

ざっくりと、いくつかのクライアントで確認せねばと書いてしまいましたが、 無数に考えられるということに、後から気づきました。

ですので、ここではいくつかのブラウザで確認することで、お茶を濁そうと思います。

具体的には、 Apache が動作しているローカルな「www.local.usupi.org」というマシンに、 IPv4とIPv6の両方のアドレスを設定します。 Apache はどちらのアドレスでも listen するよう設定しておきます。
そして、ブラウザから「http://www.local.usupi.org/」へアクセスし、 どちらのアドレスにアクセスしたか確認してみました。

試したブラウザは、以下の通りです。
(50音順です。また、動作環境は Ubuntu 10.10 です。)

結果は… Firefox 以外はみな、IPv6 のアドレスにアクセスしました。

Firefox も、「http://[fd41:28b7:be11::80]/」のように、 IPv6アドレスを直接指定すると、IPv6 でアクセスしました。
ただし、DNS で AAAA レコードだけ登録してあると、 アクセスできません的なことを言われてしまいました。

というわけで、意外と、 アプリケーション側はすでに IPv6 にも対応しているということがわかりました。 (ブラウザだけですが…)

以上、途中経過などお知らせすることが特にないため、 さらっとした答えになってしまいました。
他のクライアントに関しては、各自で確認していただけますと幸いです。

今回の宿題

今回の宿題は、

  httpd.conf から有効な「DocumentRoot」だけを抜き出しましょう。

です。

もちろん、ただ単に「DocumentRoot」で grep すればよいということではないことは、 おわかりいただけたかと思います。

というわけで、コメントや、 関係ない箇所の「DocumentRoot」を含まない正規表現を考えてみてください。

あとがき

新しい会社に勤め始めて、1ヶ月ほど経過しました。

自分でもビックリするくらい、新しい会社には慣れていません。
わからないことだらけで、あわあわしている間に1日が終わっています。

それでも、ようやくプロジェクトに参加して、 仕様書なるものを書かせていただきました。
しかも、さすがにちゃんと書けているね、なんて言われて、 年甲斐もなく有頂天になったりしてしまいました。

まあ、文章を書くことは、何歳になっても必要なことだと思います。
ちょっと雑誌で連載させてもらったからといって天狗にならず、謙虚に、 もっとよい文章が書けるよう精進したいと思います。

さて、そんなことを思っているわたしにとって、 びびびびっと心に響いた記事がありましたので、ご紹介させていただきます。

読みやすい文章を書くための技法 - #RyoAnnaBlog
http://d.hatena.ne.jp/RyoAnna/20100824/1282660678

文章を書く際に意識すべきことが、10個ほど書いてあります。
いずれも納得できることですし、理解するのに難しくはありませんので、 興味のある貴兄は、是非読んでみてください。

わたしも、順序を入れ替えてみたり、同じ表現ばかり使わないよう変えてみたり、 文章の流れを考慮したり、わざとひらがなで書いたりなどはしていました。

ですが、文章の始まりを短くするとか、PREP法などは、上記で初めて知りました。
すぐにマスターできるかどうかはわかりませんが、 少しは意識して書いていきたいと思います。

文章に限らず、すべてにおいて言えることですが、現状に満足せず、 常に向上心を持って物事に取り組んでいきたいものですね。

 

今回も、ここまで読んでいただき、たいへんありがとうございました。
次回は、3月20日(日) の未明にお会いしましょう!

 

「いますぐ実践! Linux システム管理」の解除は、以下からできます。
http://www.usupi.org/sysad/ (まぐまぐ ID:149633)

バックナンバーは、こちらにほぼ全部そろっています。
http://www.usupi.org/sysad/backno.html

「栗日記」- ここのところ気合が足りていなかったと反省中です。
http://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
http://usupi.org/k/ (モバイル栗日記)


[バックナンバーのトップへ] [Linux システム管理のトップへ]

トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ リンク

独学Linux
Linuxデスクトップ環境に関する情報が満載です。 メルマガもありますよ。
Server World
CentOS 6をサーバとしたときの設定例が、これでもかというくらいたくさん載っています。 CentOS以外のディストリビューション(Fedora, Ubuntu)も充実しています。
LINUXで自宅サーバーを構築・導入(Fedora9)
Fedora9のインストールの仕方から管理方法まで、詳しく載っています。 SearchManには情報がもりだくさんです。
マロンくん.NET
〜サーバ管理者への道〜
Linuxをサーバとして使用するための、いろいろな設定方法が載っています。 マロンくんもかわいいです。 なんといっても、マロンくんという名前がいいですね!!
日経Linux
今や数少なくなってしまったLinuxの雑誌。ニュースやガイドもあります。
Linux Square − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
SourceForge.JP Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
IBM developerWorks : Linux
開発者向けですが、勉強になりますよ。
Yahoo!ニュース - Linux
Yahoo!のLinuxに関するニュース一覧です。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)
WEB RANKING - PC関連
ランキングに参加してみました。押してやってください。

▼ 作ってみました

Add to Google

▼ せんでん




▼ 最近読んだ本

▼ 気に入ってる本