MIRACLE
メールサービス申込 ユーザー登録&ログイン パートナー情報
お問い合わせ FAQ サイトマップ
MIRACLE LINUXの特長 製品紹介 サービス案内 購入 サポート 技術フォーラム

プロフィール

日本発のリナックス企業、ミラクル・リナックスで奮闘する社員のブログです。

ミラクル関連リンク

採用情報

サイト検索

最近のトラックバック

2010年2月

  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28            

« RPMファイルへの署名(RPMコマンド) | メイン | Nokia E61 で SSH ログイン »

ruby ことはじめ - 第6回「人生いろいろ、ハッシュで色々♪」

こんばんは。ほぼ毎日行っているスポーツジムが休みのため、毎週火曜日は自宅近くの温泉に行くkyagiです。おかげで、自宅のお風呂には数えるほどしか入ったことがありません。:-)

今回はrubyを使ってターミナルのカラー出力をやってみよう、というお話です。というのも、先日お仕事で作成したスクリプトの出力をデモしてみせたところ「これじゃOKかNGかパッと見、わからないなあ」と言われたことがキッカケだったりします。

「一目瞭然な様にカスタマイズしちゃる!」と心に決めたkyagiは今までスクリプト内で使用していた平凡なprintをやめ、独自でモジュールを作成することにしました。ターミナルへの出力はLinuxのデーモンを |start|stop| した時のようにエスケープシーケンスを使ってOKをグリーンでNGをレッドでカラー表示にしてやろう、という魂胆です。データ構造としてはハッシュを使い、キーで色指定できるようにしてみました。

実はrubyでは「全てがオブジェクト」のためハッシュのキーにシンボルをそのまま使用することはできません。kyagiはいちいちキーをStringオブジェクトとして""で囲むのがメンドクサイのでキーにシンボルを使用し:symbolというふうに書くことにしました。

# ruby
× h = { apple => 120, banana => 30 }; print h[apple];
○ h = { "apple" => 120, "banana" => 30 }; print h["apple"];
○ h = { :apple => 120, :banana > 30 }; print h[:apple];

# perl
○ %h = (apple => 90, banana => 30); print $h{apple}

モジュールの名前をMessage.rbとし、スクリプト全体で使うことを考慮し、汎用的なモジュールとして設計します。後は使いたいクラスの先頭で include すればよいだけです。

#
# = Message.rb: Framework Message Module
#
# Copyright (C) 2007, Miracle Linux Corporation
# Author:: kyagi
# Documentation::
#

module Message
  Color = { :def => "", :red => "\033[0;31m", :green => "\033[0;32m",
            :brown => "\033[0;33m", :blue => "\033[0;34m",
            :purple => "\033[0;35m", :cyan => "\033[0;36m",
            :gray => "\033[0;37m" }

  def msg(str, color=:def)
    if (color == :def)
      suffix = ""
    else
      suffix = "\033[0m"
    end
    STDOUT.print Color[color] + str + suffix
    STDOUT.flush
  end

  def msg_wrn(str)
    STDOUT.puts "WARNING: " + str
    STDOUT.flush
  end

  def msg_err(str)
    STDERR.puts "ERROR: " + str
    STDOUT.flush
  end

end

ワンライナでテストした結果は以下になります。ちゃんと動いていますね:-)

Message_rb

カラー出力はシェルでも応用が効きそうだったので cecho(Color ECHO)としてシェル版も作成してみました。とりあえず自作のシェル関数のコレクションであるfunctionsというファイルに入れておきます。

cecho ()
{
        local MSG=$1
        local COLOR=$2
        local PREFIX=
        local SUFFIX="\033[0m"

        case "$COLOR" in
                red)
                        PREFIX="\033[0;31m"
                        ;;
                green)
                        PREFIX="\033[0;32m"
                        ;;
                brown)
                        PREFIX="\033[0;33m"
                        ;;
                blue)
                        PREFIX="\033[0;34m"
                        ;;
                purple)
                        PREFIX="\033[0;35m"
                        ;;
                cyan)
                        PREFIX="\033[0;36m"
                        ;;
                gray)
                        PREFIX="\033[0;37m"
                        ;;
                *)
                        PREFIX=""
                        SUFFIX=""
                        ;;
        esac

        MSG="$PREFIX$MSG$SUFFIX"
        echo -e "$MSG"
}

としているうちに、最近になってシステム管理者からftpサーバのテストを頼まれました。テストをしたのはいいのですが、下記のログを提出する際に自分の打ったコマンドだけをカラー出力するパーサも同梱するとシステム管理者に喜ばれるかもしれないと思い、作成してみることにしました。古今東西、泣く子とシステム管理者に逆らえません&機嫌を取って悪いことはありません。:-)ログは下記のようになっています。

kyagi@dhcp-0225:~/new_ftp_test$ ping -c3 219.118.163.67
PING 219.118.163.67 (219.118.163.67) 56(84) bytes of data.
64 bytes from 219.118.163.67: icmp_seq=1 ttl=254 time=0.368 ms
64 bytes from 219.118.163.67: icmp_seq=2 ttl=254 time=0.375 ms
64 bytes from 219.118.163.67: icmp_seq=3 ttl=254 time=0.388 ms

--- 219.118.163.67 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.368/0.377/0.388/0.008 ms
kyagi@dhcp-0225:~/new_ftp_test$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.1.0.0        0.0.0.0         255.255.0.0     U         0 0          0 eth0
0.0.0.0         10.1.0.1        0.0.0.0         UG        0 0          0 eth0
kyagi@dhcp-0225:~/new_ftp_test$ nslookup ftp.miraclelinux.com
Server:         10.1.0.21
Address:        10.1.0.21#53

ftp.miraclelinux.com    canonical name = ftp01.miraclelinux.com.
Name:   ftp01.miraclelinux.com
Address: 219.118.163.67

kyagi@dhcp-0225:~/new_ftp_test$ nslookup 219.118.163.67
Server:         10.1.0.21
Address:        10.1.0.21#53

Non-authoritative answer:
67.163.118.219.in-addr.arpa     canonical name = 67.64.163.118.219.in-addr.arpa.
67.64.163.118.219.in-addr.arpa  name = ftp01.miraclelinux.com.

Authoritative answers can be found from:
64.163.118.219.in-addr.arpa     nameserver = ns.miraclelinux.com.
64.163.118.219.in-addr.arpa     nameserver = ns1.bit-drive.ne.jp.
64.163.118.219.in-addr.arpa     nameserver = ftp01.miraclelinux.com.
ns.miraclelinux.com     internet address = 219.118.163.66
ns1.bit-drive.ne.jp     internet address = 211.9.32.227
ftp01.miraclelinux.com  internet address = 219.118.163.67

kyagi@dhcp-0225:~/new_ftp_test$ ftp -p 10.0.0.5
Connected to 10.0.0.5.
220 MIRACLE LINUX FTP Server
Name (10.0.0.5:kyagi): anonymous
331 Anonymous login ok, send your complete email address as your password.
Password:
230 Anonymous login ok, restrictions apply.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd pub/Miracle/3.0/updates/RPMS/
250 CWD command successful
ftp> ls Auto*
227 Entering Passive Mode (10,0,0,5,135,23).
150 Opening ASCII mode data connection for file list
-rw-r--r--   1 ftpadm   ftpadm     205605 Feb 17 04:55 AutoConfig-1-17A.i386.rpm
226 Transfer complete.
ftp> bin
200 Type set to I
ftp> put B_1_1.png
local: B_1_1.png remote: B_1_1.png
227 Entering Passive Mode (10,0,0,5,135,24).
550 B_1_1.png: Permission denied
ftp> quit
221
kyagi@dhcp-0225:~/new_ftp_test$

このログを自分の打ったコマンドだけがカラー表示になるように、上記のシェル関数 cecho と less -R を使用して readlog というスクリプトを作成してみました。こういったスクリプトは作業ログを確認するのにも一役買うのではないかと思います。

#!/bin/sh
##
## Read test result log with color
##
## Author: kyagi
## Usage : readlog test.log
##

. functions

LOG=$1
MYPROMPT="kyagi@dhcp-0225:~/new_ftp_test\\$"
while read LINE; do
        echo "$LINE" | grep -q "$MYPROMPT"
        if [ $? == 0 ]; then
                echo -n "$LINE" | awk -F"$" '{printf("%s$",$1)}'
                LINE_COLOR=`echo "$LINE" | awk -F"$" '{print $2}'`
                cecho "$LINE_COLOR" red
        else
                echo "$LINE"
        fi
done <"$LOG" | less -R -N

実験したところ、このままだと ftp セッションに入った時のカラーが色分けされていないのが気になったので、下記のパッチのように拡張してみました(その場しのぎですが)。

$ diff -c readlog readlog_with_ftp

*** readlog     2007-02-28 01:36:14.000000000 +0900
--- readlog_with_ftp    2007-02-28 01:36:37.000000000 +0900
***************
*** 10,15 ****
--- 10,16 ----

  LOG=$1
  MYPROMPT="kyagi@dhcp-0225:~/new_ftp_test\\$"
+ FTPPROMPT="ftp>"
  while read LINE; do
        echo "$LINE" | grep -q "$MYPROMPT"
        if [ $? == 0 ]; then
***************
*** 17,22 ****
                LINE_COLOR=`echo "$LINE" | awk -F"$" '{print $2}'`
                cecho "$LINE_COLOR" red
        else
!               echo "$LINE"
        fi
  done <"$LOG" | less -R -N
--- 18,30 ----
                LINE_COLOR=`echo "$LINE" | awk -F"$" '{print $2}'`
                cecho "$LINE_COLOR" red
        else
!       echo "$LINE" | grep -q "$FTPPROMPT"
!               if [ $? == 0 ]; then
!                       echo -n "$LINE" | awk -F">" '{printf("%s>",$1)}'
!                       LINE_COLOR=`echo "$LINE" | awk -F">" '{print $2}'`
!                       cecho "$LINE_COLOR" green
!               else
!                       echo "$LINE"
!               fi
        fi
  done <"$LOG" | less -R -N
./readlog_with_ftp log


Readlog

これでひとまず、落ち着きました。

ちなみに perl だと Term::ANSIColor というモジュールがあり、とっても簡単にカラー出力ができます。perldoc -m Term::ANSIColor またはCPANのページをご参照あれ。つーか最初から perl でやればよかった…orz.

追記:

tput を使用したfumiyas ししょーのサンプルスクリプト結果です。

昔の放送終了時のTVみたいだ・・・(^_^;

Fumiyas_shisyo_tput


トラックバック

このページのトラックバックURL:
http://www.typepad.jp/t/trackback/4447/6820653

このページへのトラックバック一覧 ruby ことはじめ - 第6回「人生いろいろ、ハッシュで色々♪」:

コメント

コレを使えばいいのでは。。。
http://term-ansicolor.rubyforge.org/

anaitoさん、情報ありがとうございます。

おっしゃる通りです。perlと同名で既にモジュールがあったんですね。また車輪の再発明をしてしまった・・・(T_T)

rubyforgeをもっと見るようにします。

#!bin/sh
##
## Shell Demo: tput(1) and colors
## See also terminfo(5)...
##
## Author: SATOH Fumiyasu @ OSSTech

cn=`tput colors`
cm=`expr $cn - 1`
c="`seq 0 $cm`"
for f in $c; do
for b in $c; do
tput setaf $f
tput setab $b
echo "f=$f b=$b"
done
done
tput setb 0

fumiyasししょー、コメントありがとうございます。

サンプルスクリプトの結果を追記させていただきました。tput勉強します。

最後の行は「tput setab 0」の間違いだった。

コメントを投稿

会社情報 採用情報 個人情報保護方針 商標等取り扱い事項 English
Copyright(c)2000-2006 MIRACLE LINUX CORPORATION. All Rights Reserved.