1. UNIX/Linuxを使うなら必ず知っていて欲しい正規表現

1.1. Agenda

  • 以下、説明が長いですけど、言いたい事は2つだけです。

    1. 正規表現を使いこなせるようになって欲しい

    2. grepコマンドの使い方で、こんなのは間違い

      $ grep '10.1.2.1' /var/log/messages
      

1.2. 正規表現はみんな使っている

  • 皆さんは正規表現を使ったことがありますか?

    え?そんな難しい事はやった事が無い? いえいえ、UNIX/Linuxをターミナル(TeraTermとか)から使っている人は、正規表現を必ず使っています。

    例えば皆さんはAgendaの例のような「grep」というコマンドを使ったことがあるはずです。

    Wikipediaから引用してみましょう。

    grep(グレップ)は、UnixおよびUnix風オペレーティングシステムにおけるコマンド。テキストファイル中から、正規表現に一致する行を検索して出力する。

    そう、grepコマンドで検索している時はオプションでOFFにしない限り、常に正規表現で検索している事になるのです。

    grepコマンドの他にも、sedやawk等の文字列操作のコマンドは正規表現を標準で使います。

    だから正規表現を知らないと、間違いを起こしてしまう事が十分にありえます。

1.3. 正規表現ってどんな物?

  • 適当に説明すると、アバウトに文字列をマッチさせる方法です。

    さて正規表現について説明する前に、シェル表現を知る必要があります。何故なら使う文字が似ているのに、両者は全く意味が違い、混同しやすいからです。

    • シェル表現とは?

      • Windowsのコマンドプロンプトや、Linuxのシェルで使える、*(ワイルドカード)、?(1文字にマッチするワイルドカード)などの事。
      $ ls -1 /etc/\*conf
      

      と打ち込むと、

      /etc/ld.so.conf
      /etc/nsswitch.conf
      /etc/syslog.conf
      /etc/logrotate.conf
      /etc/pam.conf
      /etc/sysctl.conf
      /etc/resolv.conf

      というように /etc 配下の、○○conf というファイル名が全て結果が帰ってきます。 「*」は正規表現では全く意味が違いますので気を付けて下さい。

  • 本題に入って、正規表現で使われる「メタ文字」

    メタ文字とは特殊な意味を持つ文字です。正規表現で使われる文字は通常の表示上そのままの意味の文字とメタ文字の2種類に分かれます。

    メタ文字について今回は3つだけご紹介します。

    . (ドット)

    任意の1文字にマッチします。

    「a」にも「b」にも「c」にも「z」にも「0」にも「9」にも「会」にも「社」にも.......1文字であればなんにでもマッチします。
    ...
    

    . (ドット)を3つ並べれば「abc」 「ddd」 「123」 「メール」 「教育部」にマッチします。

    * (アスタリスク)

    直前の正規表現を「0回」以上繰り返す文字列にマッチします。
    a*
    は「a」という正規表現を「0回」以上繰り返した物にマッチするという意味になります。
    a
    
    にマッチします。
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

    にもマッチします。0回以上なので、文字列が無い場合にもマッチします。

    それではメタ文字を組み合わせて見ましょう。

    .*

    これは、任意の1文字が0回以上繰り返される場合にマッチするという意味なので、全ての文字列にマッチします。

    じゃあ、「 . 」や「 * 」という文字自体をマッチさせる場合はどうすれば良いのでしょうか?

    \.
    \*

    メタ文字の直前にエスケープ文字「 \ 」を入れる事によって字面と同じ文字にマッチさせる事ができます。

1.4. grepコマンドで注意する事

  • ここまで来ればAgendaの 2 のgrepコマンドでどこが間違っているのか、薄々感ずいてきたのではないでしょうか?

    $ grep '10.1.2.1' /var/log/messages
    
    そう、「 . 」をエスケープしていないので字面通りの「10.1.2.1」以外にもマッチしてしまうのです。
    10.1.221
    10.162.1
    10919281.......etc

    だから「10.1.2.1」にマッチさせたい場合は、

    $ grep '^10\.1\.2\.1$' /var/log/messages
    
    というような指定の仕方が必要になります。あれ、まだ紹介していないメタ文字が出ちゃいましたね(^-^;
    ^ 先頭にマッチ
    $ 最後にマッチ

    です。覚えておきましょう。

    さらに紹介していないメタ文字を使って、こんな事もできるよっという事で。

    $ grep -Po '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' /var/log/messages
    

    これは、messagesに出力されているIPアドレスのみを抜き出すコマンドです。通常はgrepはマッチした文字列の行全てを表示してしまうのですが -o オプションを付けると正規表現でマッチした部分のみを抜き出してくる事ができます。もっとも、999.999.999.999のようなIPアドレスの範囲外にもマッチしてしまうのはご愛嬌。簡略化しているのでご容赦を。

1.5. 最後に

さて如何でしたでしょうか。もっと正規表現について知りたい!と思った方がいらっしゃれば講習を開きたいと思います。 単なる質問でも結構ですので、じゃんじゃんお便り下さいね~。