2011年12月31日土曜日

[python] 今年最後の大修整!colorizeのオプションを大幅変更!

まぁ、やったことは別に大したことではないけども。
以前作った標準出力に色を付けるコマンド colorizeの、オプション回りを修正した。
前の記事
結構派手に変えた。前のオプションは全削除。

ソースはここ。
kokukuma / python-colorize

colorizeの使い方


一番簡単な使い方はこれ。
$ colorize.py karino

任意に色を指定するために4つのオプションを持っている。
簡単な色と範囲の指定には「-c」、「-r」オプションを使用する。
cは色の指定。rは正規表現を使った範囲の指定。
使い方は、たとえばこんな感じ。
$ colorize.py -c green -r '^.*$' karino
$ colorize.py -c blue -r 'kari' karino


もっと複雑なルールを設定するために、
設定ファイルを書くことができる。
デフォルトのパスは、~/.colorize.yml
形式は見ればわかる。

たとえばこんな感じ。
$ colorize.py -s errorlog [error]

たとえばこんな感じ。
$ ping google.com | colorize.py -s ping

どんな出力になるかは、試してみてのお楽しみ。


また、デフォルトパス以外の設定ファイルを読み込むこともできる。
たとえばこんな感じ。
$ colorize.py -f '/home/karino/test_colorize.yml'  -s errorlog [error]


optparseを使ったオプション管理

大きな変更点はここ。
これを使えば、オプションと標準入力をしっかり区別することができる。
管理も楽。ヘルプもつけれる。
パーサを作成し、それを使ってオプションやそのほかの引数を取得する。

パーサの作成はこんな感じ。
def build_option_parser():    
"""Make Option Parser"""
    parser = OptionParser()
    parser.add_option(
            '-f', '--configuration-file-path',
            help="read configuration from. (default: '~/.colorize.yml')",
            default='~/.colorize.yml'
            )
    parser.add_option(
            '-s', '--color-scheme',
            help="set scheme of colorize. (default: 'all')",
            default="all"
            )
    parser.add_option(
            '-r', '--regular',
            help="set regular expression. (default: '^.*$')",
            default=r"^.*$"
            )
    parser.add_option(
            '-c', '--color',
            help="set color. (default: 'red')",
            default="red"
            )
    return parser

オプション・引数の取得はこんな感じ。
parser = build_option_parser()
    opts, args = parser.parse_args()

    # get options / color_scheme
    try:
        config_path = opts.configuration_file_path
        color_scheme = opts.color_scheme

        if color_scheme == 'all':
            color_scheme = [{
                    'regular':'(' + opts.regular + ')',
                    'color':opts.color
                    }]
        else:
            color_scheme = read_color_scheme(color_scheme, config_path)

    except Exception, e:
        parser.error(e)

[vim][python] ふははは!読める!読めるぞ!

その経緯


pythonを書くとき、classやdefを折りたたむためのスクリプトを書こうと思いました。

とりあえず探してみると、あった。
python_fold : Folding expression for python

中身を見てみて、少しテンションあがった。

読める!。downloadしてきたプラグインが読める!

少しはvim scriptが読めるようになってきました。

このpython_foldを読んでみた感想は・・・。
長い。そして、if文の嵐。
個人的に使うならもっとコンパクトにまとめれそうな気がしました。



理想


ロジックとしては、以下のような感じ。
① classやdefを見つけたら、その行のインデントにあわせて、fold開始。
② 直下が空行かつ、次の非空行のインデントが現在のfoldlevelより小さければ、foldを閉じる。
③ それ以外の場合は、前の行と同じ操作。

これをvim scriptで書くとこんな感じになるはず。

" 折り畳みレベルを設定する関数(python)
function! PYTHONFoldSetting(lnum)

    " 現在の行
    let line = getline(a:lnum)
    let ind  = indent(a:lnum)
    let flev = foldlevel(a:lnum)

    " 次の行
    let line1 = getline(a:lnum + 1)

    " 次の非空行
    let nind = indent(nextnonblank(a:lnum + 1))

    " Classes and functions get their own folds
    if line =~ '^\s*\(class\|def\)\s'
        return '>'. (ind / &sw + 1)
    elseif empty(line1) && (nind / &sw + 1) <= flev
        return '<'.flev
    else
        return '='
    endif
endfunction
しかし、動かないorz。 foldlevel関数でとってこれてないのかな・・。


妥協

どうしても動かないので、 仕方なしで以下のように妥協。
function! PYTHONFoldSetting(lnum)
    " foldlevelは3まで
    set foldnestmax=3

    " 現在の行
    let line = getline(a:lnum)
    let ind  = indent(a:lnum)
    let flev = foldlevel(a:lnum)

    " 次の行
    let line1 = getline(a:lnum + 1)

    " 次の非空行
    let nind = indent( nextnonblank(a:lnum + 1) )

    " Classes and functions get their own folds
    if line =~ '^\s*\(class\|def\)\s'
        return '>'. (ind / &sw + 1)
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 1
        return '<'.1
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 2
        return '<2'
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 3
        return '<3'
    else
        return '='
    endif
endfunction

まぁ動作としては変わらないし、3段階以上ネストすることもないだろうから、
実用上これで良いかもしれないが、
やっぱ気持ち悪いな・・・。

[vim] カーソル下のキーワードをhelp検索するためのキーバインド

カーソルの下にある単語でvimのhelpを引くためのキーバインド。
なんのことはない単純な設定だが、異常に便利。

nnoremap <C-h> :<C-u>help<Space><C-r><C-w><CR>

今まで、:h getline とか打ってたのが馬鹿みたい。


その後・・・。
やっぱこっちにした↓
nnoremap H; :<C-u>help<Space><C-r><C-w><CR>

2011年12月29日木曜日

[vim] phpのfunctionを折りたたむ設定をした。

目指せ!一日 一vimscript.

IDEでよく見るfunction毎に行を折りたたむあれ。
これをやると、


が、




こんな感じになる。
絵、見づらいな。

ここを参考にしました。
折り畳み嫌いの男が一夜でFolding freakにまでなった話



folding設定のやり方

foldmethodにexprを指定すれば、
行ごとに、どのようにfoldingするかを指定することができる。
foldmethodにはほかにもいくつか指定方法があるが今回はこれで。


php用の設定

phpの場合、この関数で定義される条件に沿ってfoldingする。
function! PHPFoldSetting(lnum)
    let l:line = getline(a:lnum)
    if l:line =~ 'function'
        return '>1'
    elseif getline(a:lnum + 1) =~ ' \* '
        return 0
    elseif getline(a:lnum) =~ ' \* '
        return 0    
    else        
        return '='    
    endif
endfunction


bash用の設定

bashの場合、この関数で定義される条件に沿ってfoldingする。
function! BASHFoldSetting(lnum)
    let l:line = getline(a:lnum)
    if l:line =~ '^.*() {'
        return '>1'
    elseif getline(a:lnum) =~ '^}'
        return '<1'
    elseif getline(a:lnum - 1) =~ '^}'
        return '0'
    else
        return '='
    endif
endfunction

ファイルオープン時の設定読み込み

phpならPHPFoldSetting、bashならBASHFoldSettingを読み込む。
autocmd BufEnter *.php set foldmethod=expr foldexpr=PHPFoldSetting(v:lnum)
autocmd BufEnter .bashrc set foldmethod=expr foldexpr=BASHFoldSetting(v:lnum)

キーバインドを設定

" folding用キーバインド
noremap [space] 
nmap  [space]
noremap [space]j zj
noremap [space]l zo
noremap [space]k zk
noremap [space]h zc
noremap [space]i zMzv
noremap [space]m zm


これ、便利だわ。

2011年12月28日水曜日

[vim] 日本語ヘルプをインストール

最近、何かと、vimのヘルプを参照する機会が多くなってきた。
日本語でよもう。
vim scriptでわからないことものあったら、
ググるよりヘルプ見た方がいい。

日本語に翻訳されたvimエディタのヘルプをインストールして使用する。
ここの↑劣化コピー。


インストール

① 日本語ヘルプをダウンロード
コマンドラインで以下を実行。
git clone git://github.com/vim-jp/vimdoc-ja.git
cd vimdoc-ja
cp doc/* ~/.vim/doc

② ヘルプの設定
以下をvimrcに書き込む。
helptags ~/.vim/doc
set helplang=ja,en

ヘルプの引き方


: h (調べたいこと)
: helpg (調べたいこと)
h → help
helpg → helpgrep

英語のヘルプを引きたいときは。


: h (検索したいこと)@en
@jaをつければ日本語。

2011年12月27日火曜日

[vim] vimを起動したカレントディレクトリを見て、参照するtagファイルを変える方法。

そろそろ、タグジャンプが使いたくなってきたので、ctagsをインストール・設定した。


ctagsインストール

$ sudo yum install ctags

適当にインストール。

ctagsのタグ作成手順・シェル


$ ctags -f ./tags -R ./lib/model/
$ ctags -a -f ./tags -R ./lib/util/ 
-f : tagファイルの名前を指定
-R : 再帰的にディレクトリを参照
-a : 既存tagファイルがあれば末尾から追記。

普段、参照先のモデルやライブラリを大きく変更する事はないので、
bazarlレポジトリのアップデートと一緒にtagファイルを作成するように
シェルに組み込んだ。

ctagsの設定ファイルもあるらしいが、
シェルに書いとけば良いやと思って調べてない。


tags読み込み

下記を、vimrcに書き込んだ。
let current_dir = expand("%:p:h")
" 開くディレクトリによって、読み込むtagsを切り替える
if matchstr(current_dir , "tsubasa_source/tsubasa/") == "tsubasa_source/tsubasa/"
    set tags=/home/karino/tsubasa_source/tsubasa/tags
endif
if matchstr(current_dir , "tsubasa_source/tsubasa_invite_incentive") == "tsubasa_source/tsubasa_invite_incentive"
    set tags=/home/karino/tsubasa_source/tsubasa_invite_incentive/tags
endif

vimを起動したディレクトリを取得し、
特定のディレクトリ名がマッチしたら、
tagsファイルを読み込む。
「tsubasa_source/tsubasa」を含むなら、tsubasa/tags。
「tsubasa_source/tsubasa_invite_incentive」を含むなら、tsubasa_invite_incentive/tags。
見たいな感じ。

これだけなのに調べるの結構大変だった。

2011年12月24日土曜日

[vim] NERDTreeをインストール

NERD-Tree

Vim Essential Plugin: NERDTree

便利そうだったので入れた。
加えて、初めて、autocmd使った
vimの設定をしてみた。

① インストール

The NERD tree : A tree explorer plugin for navigating the filesystem
からダウンロード。

$ wget http://www.vim.org/scripts/download_script.php?src_id=11834
$ mv download_script.php\?src_id\=11834 ds.zip
$ unzip ds.zip
$ cp doc ~/.vim/
$ cp nerdtree_plugin ~/.vim/
$ cp plugin ~/.vim/


② grep機能の追加

nerdtree plugin to integrate nerdtree with :grep : Forked from
$ wget https://gist.github.com/gists/414375/download
$ mv download dl.tar.gz
$ tar -xvzf dl.tar.gz
$ cd gist414375-24c6049f621f07db839e8cdd133e396756d642db/
$ cp grep_menuitem.vim ~/.vim/nerdtree_plugin/


③ 基本的な使い方

NERDTree : ツリー型エクスプローラ
起動:コマンドモードでNERDTree

o : ディレクトリを開く or ファイルを開く
O : 再帰的にディレクトリを開く
s : 縦に開く
m : メニューを開く


④ 使いやすいように設定

引数なしでvimを開いたらNERDTreeを起動、引数ありならNERDTreeは起動しないように
vimrcに以下を記述した。
let file_name = expand("%")
if has('vim_starting') &&  file_name == ""
    autocmd VimEnter * NERDTree ./
endif

2011年12月23日金曜日

LinuxにDropboxをインストールする。

LinuxにDropboxをインストールしてみた。
かなり便利。

さくらVPSでDropboxをX11なしで使う

① シェルをダウンロード
$ wget http://www.dropbox.com/download?dl=packages/dropbox.py
$ chmod 777 dropbox.py

② 起動すると、dropboxのダウンロードが始まる。
$ ./dropbox.py start
Starting Dropbox...
The Dropbox daemon is not installed!
Run "dropbox start -i" to install the daemon
$ ./dropbox start -i
Starting Dropbox...
Dropbox is the easiest way to share and store your files online. Want to learn more? Head to http://www.dropbox.com/

In order to use Dropbox, you must download the proprietary daemon. [y/n] y
Downloading Dropbox... 100%
Unpacking Dropbox... 100%
Dropbox isn't running!
Done!

③ マシンとアカウントをリンクする。
$ ./.dropbox-dist/dropbox
このクライアントはアカウントにリンクされていません...
このマシンをリンクするには https://www.dropbox.com/cli_link?host_id=792418c797c32c59202ee249101a5bfc&cl=ja を開いてください。
このクライアントはアカウントにリンクされていません...
このマシンをリンクするには https://www.dropbox.com/cli_link?host_id=792418c797c32c59202ee249101a5bfc&cl=ja を開いてください。
・・・

シェルをこのままにして、別のPCからでもURLへ接続して、Dropboxにログインする。


④ Dropboxのデーモンを起動する
$ ./dropbox.py start
Starting Dropbox...Dropbox isn't running!
Done!

これで、HOMEにできたDropboxがリンクする。

2011年12月18日日曜日

「標準出力に色をつけたい!」と思ったときは、このコマンド使ったらいいと思う。

「標準出力の色を変更するためのコマンド」を作った。

これを使えば、tailしているログに任意に色をつける事はもちろん、
pingなど標準出力されるもの全部に色をつける事ができる。
複雑な着色ルールでも、yaml形式の設定ファイルで簡単に設定できる。
結構うまくできた気がする。

経緯

この前、標準出力に色をつける方法を知った。
そのログ、色つきでtailしたくないですか?

ふと探してみると、色つきtailがあった。
pctail - CCZE に似た、Python で書かれた色つき Tail
やってる事は同じ。何を使って置換するかが違うだけかな。

チョット読んでみたが・・・、色のつけ方いまいち。
せめて、IPアドレスは色変えてほしい。

そしてログだけではもったいない。
いろんなコマンドの標準出力に色をつけたい。

しかし、前みたいにperlをパイプラインでつなぎまくるのはいけてない。(って言われたw)遅くなるし。
そこで、標準出力の色を変更するためのコマンドを作った。


ソース


結構長くなったので、githubに置く。
kokukuma / python-colorize

初めてpython書いたので、
めんどくさい書き方してる場合があるかも知れない。
誰か治してくれないかな・・・。

あ、pyyaml、インストールしておいてください。
PyYAMLモジュールを使ってPythonからYAMLを読む


使い方

$ colorize -a (色) (対象文字列)
$ colorize -r (カラールール名) (対象文字列)
1つ目の書き方では、対象文字列すべてが色変更の対象となる。
2つ目の書き方では、対象文字列を指定したカラールールに則って色変更を行う。
カラールールの形式はyml。
ルール名の下に、マッチさせる正規表現と色を指定する。
正規表現はダブルコーテーションで囲む。

(カラールール名):
    (ルール名):
        regular:"(対象文字列をあらわす正規表現)"
        color:(色)
    (ルール名):
        regular:"(対象文字列をあらわす正規表現)"
        color:(色)


使用例

tailしているログに色をつけたい場合はこんな感じ。
$ tail -f log |  colorize -a errorlog

pingに色をつけたい場合はこんな感じ。
$ ping google.com | colorize -a ping

このとき使っているconfig.ymlはこんな感じ。
errorlog:
    rule1:
        regular:"\[[Ee]rror\]"
        color:red
    rule2:
        regular:"\[emerg\]"
        color:green
ping:
    rule1:
        regular:"[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"
        color:yellow
    rule2:
        regular:"[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"
        color:under
    rule3:
        regular:"from"
        color:red

その後、
前後にgrepつけれない問題はまだ残っている。。
結構致命傷だな。

2011年12月15日木曜日

もう何度も何度もやっている気がするが、今後また作るときの事を考えて、改めてここで、PHP Extension の作り方をまとめておく。

自分がPHP Extensionを作ろうと思ったときに、
「とりあえず開いて書き方ぱくるためのページ」として、
これを書いておく。解説は他のサイトを確認する。
Zend API: PHPのコアをハックする
ここはあくまで、こうやって書いたら動いたってメモ。

※ 前提条件として、PHPをソースからコンパイルしてある事とする。

ソースのパス : /usr/local/share/php-5.3.8/
extension_dir: /usr/lib64/20090626
作成するextensionの名前: mywork


1、スケルトンの作成




cd /usr/local/share/php-5.3.8/ext/
./ext_skel --extname=mywork
cd mywork


2、とりあえずコンパイル




① config.m4を修正
inl 以下をコメントアウトからはずす。
PHP_ARG_WITH(eigen, for eigen support,
Make sure that the comment is aligned:
[  --with-eigen             Include eigen support])

② コンパイル
# phpize 
# ./configure
# make
これで、./modules内に、mywork.soが作成される。
されなかったらなんか間違ってる。

③ PHPにextensionを読み込ませる。
# ln -s /usr/local/share/php-5.3.8/ext/mywork/modules/mywork.so /usr/lib64/20090626/
加えて、php.iniに「extension=mywork.so」を記入しておく。
make installしても良いが、これから何度もコンパイルするたびにmake installするのがめんどくさいから、シンボリックリンクはる。



3、引数取得・戻値返却



こんなPHP extensionを書くためにやる事。


① php_mywork.h
// 関数名を定義
PHP_FUNCTION(MYWORK);

② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
    PHP_FE(confirm_kakasi_compiled, NULL)       /* For testing, remove later. */
    PHP_FE(MYWORK, NULL)
    PHP_FE_END  /* Must be the last line in kakasi_functions[] */
};

~~~
PHP_FUNCTION(MYWORK){    
    // 値定義
    int   str_len;
    char *str;

    // 引数の取得
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
        "s", &str, &str_len) == FAILURE) {
        return;
    }
  // 戻り値作成(文字列)
  RETURN_STRINGL(str,str_len,0);
}
これで、引数「引数」が戻される。
longやdoubleなどの返却は、同じようなマクロを使って返却する。詳しくは、以下を参照。
Zend API: PHPのコアをハックする
配列やオブジェクトの返却はチョットややこしい。

・配列を返却
PHP_FUNCTION(MYWORK){    

~~~
  // zvalの定義
  
    zval *return_array;
    char *separated_word
    char words[1024];
    words="test,test,test,test";

  // 配列を表すzvalを作成
    MAKE_STD_ZVAL(return_array);
    if(array_init(return_array) != SUCCESS){}

    // 文字の分割 
    separated_word = strtok( words, "," );
    while( separated_word != NULL ){
        // 配列に値を追加する。
        add_next_index_stringl(return_array,separated_word,strlen(separated_word),1);
        separated_word= strtok( NULL, "," );  /* 2回目以降 */
    }

    // 配列を返却
    *return_value = *return_array;
    zval_copy_ctor(return_value);
}

・オブジェクトを返却
PHP_FUNCTION(MYWORK){    

~~~
    // 返却オブジェクトの生成
    zval *wordset;
    MAKE_STD_ZVAL(wordset);
    if(object_init(wordset) != SUCCESS){}

    // プロパティを設定
    add_property_stringl(wordset,"base",str,strlen(str), 1);
    add_property_stringl(wordset,"hira",hira,strlen(hira),1);
    add_property_stringl(wordset,"kata",kata,strlen(kata),1);
    add_property_stringl(wordset,"alph",alph,strlen(alph),1);

    // オブジェクトの返却
    *return_value = *wordset;
    zval_copy_ctor(return_value);
}



3、クラス作成



こんなPHP extensionを書くためにやる事。
member1;
$obj->member2;
$ret = $obj->method();
?>

① php_mywork.h
// 以下を追記する。
PHP_FUNCTION(mywork);
PHP_METHOD(mywork, method);
static zend_class_entry *mywork_ce;

② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
    PHP_FE(confirm_kakasi_compiled, NULL)       /* For testing, remove later. */
    PHP_FE(MYWORK, NULL)
    PHP_ME(MYWORK, method ,NULL)
    PHP_FE_END  /* Must be the last line in kakasi_functions[] */
};

~~~
/* PHP_MINIT_FUNCTION(mywork) の中に、MYWORKの行を追記 */
PHP_MINIT_FUNCTION(mywork)
{
    /* If you have INI entries, uncomment these lines
     REGISTER_INI_ENTRIES();
    */
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "", mywork_functions);
    mywork_ce = zend_register_internal_class(&ce TSRMLS_CC);

    zend_declare_property_string(mywork_ce,"member1", strlen("member1"),"初期値", ZEND_ACC_PUBLIC);
    zend_declare_property_string(mywork_ce,"member2", strlen("member2"),"初期値", ZEND_ACC_PUBLIC);

    return SUCCESS;
}

~~~
PHP_FUNCTION(mywork){
    return;
}

PHP_METHOD(mywork, method){

    // 定義
    zval *obj, *member1, *member2;

    // メンバ変数の取得
    obj = getThis();
    member1 = zend_read_property(Z_OBJCE_P(obj),obj, "member1",strlen("member1"), 1 TSRMLS_CC);
    member2 = zend_read_property(Z_OBJCE_P(obj),obj, "member2",strlen("member2"), 1 TSRMLS_CC);
    
  // 戻り値作成(文字列)
  RETURN_STRINGL(member1,strlen(member1),0);
}



番外、C++を使いたい場合



CではなくC++を使いたい場合の今までと異なる点を上げる。

① config.m4
inl コンパイラの環境変数を設定
CC=/usr/bin/gcc
CFLAGS="-g -O2 -lstdc++"
CXX=/usr/bin/g++
CXXFLAGS=-fPIC

~~~
inl 拡張子をc→ccに変更する。
PHP_NEW_EXTENSION(eigen, eigen.cc, $ext_shared)


② ファイルの拡張子
mv mywork.c mywork.cc

③ mywork.cc
// #includeを extern "C"で囲む
extern "C"{
    #include "php.h"
    #include "php_ini.h"
    #include "ext/standard/info.h"
    #include "php_eigen.h"
}



2011年12月14日水曜日

そのログ、色つきでtailしたくないですか?

tailは便利だけど、白黒で見るのはすごく疲れます。
なので、色を付けてみたいと思います。
色をつけるにはANSI エスケープシーケンスを使えばよいらしい。


1、ANSI エスケープシーケンスとは。



ディスプレイに文字を表示する際のエスケープ。
つまり、今自分が使っているターミナルが、
受け取った文字列を表示する際の制御文字みたいなものらしい。

ANSI エスケープシーケンスを使うと、色を変えるだけでなく、
コマンドラインの表示をいろいろカスタムできるらしい。
ANSIエスケープシーケンスを使って端末に時計を表示するとか。

2、ANSIエスケープの書き方。


こんな感じ。
# karinoを赤色で標準出力
echo -e "\033[0;31mkarino\033[0m"

# karinoの背景を緑色で標準出力
echo -e "\033[42mkarino\033[0m"

# karinoにアンダーラインをつけて標準出力
echo -e "\033[4mkarino\033[0m"

複雑に見えるが、形式を把握できれば大丈夫。

5. ANSI エスケープシーケンス: 色とカーソル操作

色を変えるときの形式は、以下。
ESC[色m

bashでは以下のように書く。
「ESC」 → 「 \e 」or「 \033 」
「 [ 」 → 「 \[ 」

「色」の部分は、以下。
文字の色、背景の色、どちらもこのIDで指定する。
色ではないが下線とか点滅もできる。
【文字色】
Black 0;30
Blue 0;34
Green 0;32
Cyan 0;36
Red 0;31
Purple 0;35
Brown 0;33
Light Gray 0;37
Dark Gray 1;30
Light Blue 1;34
Light Green 1;32
Light Cyan 1;36
Light Red 1;31
Light Purple 1;35
Yellow 1;33
White 1;37

【背景色】
Black 40
Blue 44
Cyan 46
Red 41
Purple 45
Brown 43
Light Gray 47

【その他】
下線 4
点滅 5
色の逆転 7
非表示 8


3、マッチした部分を置き換える方法



標準出力されるログをハイライトさせる方法として、
以下のようなのがあった。
tail -f messages | perl -pe 's/[Ee]rror/¥e[1;31;43m$&¥e[0m/g' 
標準出力のキーワードをハイライト

これと同じ方法を使わせてもらう。


4、色を変えるスクリプト



loghighlight() {
    
    # ANSIエスケープシーケンスの定義
    RED_WORD="\e[0;31m"
    BLUE_WORD="\e[0;34m"
    GREEN_WORD="\e[0;32m"
    CYAN_WORD="\e[0;36m"
    PURPLE_WORD="\e[0;35m"
    YELLOW_WORD="\e[1;33m"
    GRAY_WORD="\e[0;37m"
    UNDER_LINE="\e[4m"
    DEFO="\e[0m"
    
    # 置換 
    while read line;do
    echo $line | /usr/bin/perl -pe "s/\[[Ee]rror\]/${RED_WORD}$&${DEFO}/g"    \
               | /usr/bin/perl -pe "s/\[client.*\]/${GREEN_WORD}$&${DEFO}/g"  \
               | /usr/bin/perl -pe "s/\[debug\]/${GREEN_WORD}$&${DEFO}/g"     \
               | /usr/bin/perl -pe "s/\[emerg\]/${GREEN_WORD}$&${DEFO}/g"     \
               | /usr/bin/perl -pe "s/\/(.*\/)(.*)/${PURPLE_WORD}$&${DEFO}/g" \
               | /usr/bin/perl -pe "s/\/(.*\/)(.*)/${UNDER_LINE}$&${DEFO}/g"  \
               | /usr/bin/perl -pe "s/PHP Fatal error:/${RED_WORD}$&${DEFO}/g"
    done
}

使い方は以下のとおり。
$ tail -f error.log | loghighlight
正規表現にマッチしたものを指定した色に変更して出力する。


5、問題点



遅い。
sedとか、awk getline使ったほうが速いかも。
whileとawk
全部perlで組んだほうがいいんじゃないだろうか。


その他、参考になったページ



Linux上でシェルが実行される仕組みを,体系的に理解しよう (bash 中級者への道)

ANSI Escape sequences


使っているうちに、いくつか問題が見つかった。
・tailの対象ファイルが2つ以上の場合、最初のファイル以外が出力されない。
・tailコマンドの前で、grep等をパイプで渡したものをloghighlightの対象とすると、ひとつも表示されない。
やっぱりwhile read以外でやりたいな。

その後、標準出力に色つけるコマンド作った。
「標準出力に色をつけたい!」と思ったときは、このコマンド使ったらいいと思う。

2011年12月8日木曜日

PHPで、漢字 → ひらがなに変換する方法を知っていますか?

mb_convert_kanaを使えば、
全角半角変換や、ひらがな→カタカナの変換は可能。
しかし、漢字→ひらがなの変換はできない。

関数リファレンス

漢字→ひらがなの変換をするためには
Mecabを使うかKakasiを使う必要がある。たぶん。
Mecabはphp拡張モジュールが準備されているが、
Kakasiはそれらしいものがなかった。

kakasiを使うPHP拡張モジュールを書いた。

php-kakasi

これを使えば、下のコードのように、
与えた文字列を、ひらがな、カタカナ、アルファベットに
変換することができる。
与える文字列は、ひらがな、カタカナ、漢字に対応している。

$kakasi = new KAKASI();
    $kakasi->word = "キャプテン翼";

    $wordset = $kakasi->reproc();

    echo "元キーワード:".$wordset->base."\n";
    echo "ひらがな変換:".$wordset->hira."\n";
    echo "カタカナ変換:".$wordset->kata."\n";
    echo "Alphabet変換:".$wordset->alph."\n";

この出力は以下。

$ php php_kakasi.php 
元キーワード:キャプテン翼
ひらがな変換:きゃぷてんつばさ
カタカナ変換:キャプテンツバサ
Alphabet変換:kyaputentsubasa


① インストール方法

こんな雰囲気。

$ git clone git@github.com:kokukuma/php-kakasi.git
$ cd php-kakasi/kakasi
$ phpize
$ ./configure
$ make
$ make install

あと、php.iniに、
「extension=kakasi.so」
って、書く。

※ kakasiは事前にインストールしておく。
※ もしかしたら、kakasi.so.2をincludeパスに移動 or ln -s する必要あるかも


その後、結構仕様変えちゃいましたw。
READMEよんでね。

2011年12月5日月曜日

対話的にBazaarを使うシェルを書いた。

今の開発環境でバージョン管理ツールにBazaarを使っているので、
よく使うコマンドをざっとメモった。
また、開発スタイルは集中型。

Bazaarユーザガイド

【開発スタイル】
① 集中型
集中型の開発
集中型の場合、全員で同じブランチを使う。
コミットするとローカルではなく、
マスターブランチにコミットされる。

② 分散型
分散型の開発
分散型の場合、開発者毎に自分のブランチを持つことになる。
コミットするとローカルブランチにコミットされ、
プッシュ・マージすることにより、
マスターブランチにアップする。


【コマンドまとめ】
① 初期設定で使うコマンド
$ bzr whoami (ユーザ名)<(メールアドレス)> // ユーザ名を設定する。
$ bzr checkout bzr+ssh://(レポジトリ先)   // チェックアウトを作成する。
$ bzr bind bzr+ssh://(レポジトリ先)       // コミットが行われるマスターブランチを変更する。
$ bzr unbind bzr+ssh://(レポジトリ先)     // コミットがローカルのみで行われるようにする。


② 日々の開発で使うコマンド
$ bzr status                     
$ bzr update                     
$ bzr log --forward --line       
$ bzr diff                       
$ bzr di                         
$ bzr marge                      


③ 今の開発環境では使わないコマンド
$ bzr clone bzr+ssh://(レポジトリ先) // クローン
$ bzr push bzr+ssh://(レポジトリ先)  // プッシュ
$ bzr pull                           // プル

今の開発環境は、「集中型の開発環境」であるので、
ローカルブランチを作成するクローンとかは使わない。


【カスタマイズ】

さらによく使う組み合わせでbashで関数を作ってみた。

① 対話型コミットシェル
変更点、コミットメッセージの入力を対話的にやってみた。
コマンド打ったほうが速い気もしなくもないが。

bzrc() {
    #--- check commit
    stty intr ^\?    
  stty erase ^H    
  
  #--- check commit  
    #bzr update
    bzr di

    #--- confirm commit  
    echo -n "Do you want commit? y or n> "
    read FLG_COMMIT

    if [ $FLG_COMMIT = 'y' ]; then
        echo ""
    elif [ $FLG_COMMIT = 'n' ]; then
        echo "Thank you."
        return
    else
        echo "Please Input y or n."
        return
    fi

    #--- get commit message 
    echo -n "Please input commit message > "
    read COMMIT_MSG

    #--- execute commit
    bzr commit "-m" "$COMMIT_MSG"
}

stty ~ ktermでバックスペースが効かない!
「stty ^H」は、入力待ちの段階で、バックスペースを効かせるために必要。

② 修正ファイルのピックアップ
リビジョン番号を渡すと、そのリビジョンで
修正されたファイルをピックアップしてくれる。
まぁ、bzr diffから文字列切り出してるだけだけど。

chkfile() {
    #--- get parameter  
    REV_NUMBER=$1

    if [ "${REV_NUMBER:-null}" = "null" ]; then
        echo
        echo "chkfile revision_number"
        echo
        return
    fi

    #--- execute bzr diff -c
    echo
    echo "=== add files"
    bzr "diff" "-c" "$REV_NUMBER" |
        grep     "=== added file "    |
        sed -e "s/=== added file '\(.*\)'/\1/"
    echo
    echo "=== modified files"
    bzr "diff" "-c" "$REV_NUMBER" |
        grep     "=== modified file "    |
        sed -e "s/=== modified file '\(.*\)'/\1/"
    echo

    return
}

③ リリースブランチへのマージ
merge() {
    #--- check commit
    stty intr ^\?          
    stty erase ^H
    
    #--- get and set parameter      
    RELESE_BRANCH="/home/karino/release"    
    TRUNK_BRANCH="/home/karino/tsubasa"    
    REV_NUMBER=$1    
    CDIR=`pwd`    
    
    #--- check parameter     
    if [ "${REV_NUMBER:-null}" = "null" ]; then        
     echo       
     echo "Please input revision_number"        
     echo        
    return    
    else        
     echo    
    fi


    #--- get commit message     
    echo "relese blanch : "$RELESE_BRANCH     
    echo "trunk blanch  : "$TRUNK_BRANCH  
    echo    echo -n "Do you want relese? (y/n) > "    
    read FLG_RELESE    
    
    if [ $FLG_RELESE = "y" ]; then        
     echo         
     cd $RELESE_BRANCH        
     bzr merge "--force -c " "$REV_NUMBER"        
     cd $CDIR    
    elif [ $FLG_RELESE = "n" ]; then        
     echo         
     echo "Thank you."
        echo
        return
    else
        echo 
        echo "Please Input y or n."
        echo
        return
    fi

    #--- return 
    return
}

KAKASIをCから使う。

cからkakasiを使う方法。
参考 : kakasi-2.3.4/doc/README.lib


① ソース
#include 
#include 
#include 
#include 
#include 
#define MYBUFSZ 1024
int UtfToEuc(char *str , char *outs);
int EucToUtf(char *str , char *outs);

int
main(int argc, char *argv[]){    
//--    
    char *srcStr, *dstStr;    
    char *srcStr2, *dstStr2;    
    char buffer[256];    
    int  strLen;    
    char *option[] = { "kakasi", "-JH"};   
    int ret;   
 //--   
    srcStr  = argv[1];   
    srcStr2 = srcStr;    
    UtfToEuc(srcStr,srcStr2);    
    ret = kakasi_getopt_argv(2, option);   
    if(ret == 0)
    {       
        dstStr2 = kakasi_do(srcStr2);       
        dstStr  = dstStr2;        
        printf(dstStr2);        
        if(dstStr2)
        {
            //--
            EucToUtf(dstStr2,dstStr);
            printf(dstStr);
            kakasi_free(dstStr2);
            dstStr  = NULL;
            dstStr2 = NULL;
            return 1;
        }
        else
        {
            printf("ERROR2\n");
        }
    }
    else
    {
        printf("ERROR1\n");
    }

    return 0;
}

int EucToUtf(char *str , char *outs)
{
    iconv_t ic;
    char str_in[MYBUFSZ+1];
    char str_out[MYBUFSZ+1];    char *ptr_in = str_in;
    char *ptr_out = str_out;
    size_t mybufsz = (size_t)MYBUFSZ;

    strcpy(str_in,str);
    ic = iconv_open("UTF-8","EUC-JP");
    iconv(ic, &ptr_in, &mybufsz, &ptr_out, &mybufsz);
    iconv_close(ic);
    strcpy(outs,str_out);

    return 0;
}

int UtfToEuc(char *str , char *outs)
{
    iconv_t ic;
    char str_in[MYBUFSZ+1];
    char str_out[MYBUFSZ+1];

    char *ptr_in = str_in;
    char *ptr_out = str_out;
    size_t mybufsz = (size_t)MYBUFSZ;

    strcpy(str_in,str);
    ic = iconv_open("EUC-JP","UTF-8");
    iconv(ic, &ptr_in, &mybufsz, &ptr_out, &mybufsz);
    iconv_close(ic);
    strcpy(outs,str_out);

    return 0;
}

ぶっちゃけ、Cよくわからず、適当に作った感は否めない。
今度ちゃんとCの勉強しよう。
って、いっつもも思う。


② コンパイル
$ sudo ln -s /usr/local/lib/libkakasi.so.2 /usr/lib64/libkakasi.so.2
$ gcc -lkakasi -o kakasi kakasi.c

普通にインストールしたら、/usr/local/lib/にsoファイルができた。
cから使おうとすると/usr/lib64から読もうとしていたので、
シンボリックリングを張った。


③ 実行
$./kakasi 狩野達也
かのたつや

辞書、追加しようかな。

漢字→かな(ローマ字)変換プログラム KAKASIのインストールと使い方

漢字→かな(ローマ字)変換プログラム KAKASI
漢字とかひらがなとかに変換するツール。

① kakasiのインストール、
$ wget http://kakasi.namazu.org/stable/kakasi-2.3.4.tar.gz
$ tar zxvf kakasi-2.3.4.tar.gz
$ cd kakasi-2.3.4
$ ./configure
$ make
$ sudo make install
普通どおり。

2、コマンドラインからの利用
[karino@115x125x111x181 ~]$cat test
漢字混じりの文章
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | nkf -w
かんじまじりのぶんしょう
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | kakasi -Hk |nkf -w
カンジマジリノブンショウ
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | kakasi -Ha |nkf -w
kanjimajirinobunshou

変換前と変換後を指定する。

J : 漢字
H : ひらがな
a : ローマ字
K : カタカナ

※ kakasiはeuc-jiで動作するようなので、
使用する前後で文字コードを入れ替えている。


3、辞書の追加
kakasi に辞書を追加する。
こんなかんじ。


追記
カタカナ、小文字「k」じゃなくて大文字「K」
にしないと効かなかった。

-JH : 漢字→ひらがな
-KH : カタカナ→ひらがな
-Ha : ひらがな→アルファベット

2011年12月1日木曜日

対話的にデプロイを行うシェルを書いた。

サーバ側にある対話型デプロイツールを使うとき、
いちいちサーバにsshするのがめんどくさいので、
シェルを書いてみた。

expectコマンドの使い方

対話型アプリケーションを自動実行する
対話型のコマンドを自動化できるexpectコマンド
[expect] spawnしたプロセスの終了ステータスを得る


① 対話型リモートデプロイシェル
まず、expectをインストール(apt-get install expect)
deploy() {
    #--- for backspace  
    stty intr ^\?
    stty erase ^H

    #--- get parameter  
    DEPLOY_ENV=$1

    #--- confirm commit  
    if [ "${DEPLOY_ENV:-null}" = "null" ]; then
        echo
        echo "deploy type"
        echo "type :  tst # kg_tsubasa.dev.klabgames.net"
        echo "        stg # kg_tsubasa.klabgames.net"
        echo
        return

    elif [ $DEPLOY_ENV = 'tst' ]; then
        DEPLOY_SERVER="tsubasa.dev.klabgames.net"

    elif [ $DEPLOY_ENV = 'stg' ]; then
        DEPLOY_SERVER="tsubasa.klabgames.net"

    else
        echo
        echo "deploy type"
        echo "type :  tst # kg_tsubasa.dev.klabgames.net"
        echo "        stg # kg_tsubasa.klabgames.net"
        echo
        return
    fi
    #--- which deploy  
    echo
    echo -n "Which Deploy (site:s / mgr:m) > "
    read FLG_DEPLOY_TYPE

    if [ "${FLG_DEPLOY_TYPE:-null}" = "s" ]; then
        DEPLOY_TYPE="site"
    elif [ "${FLG_DEPLOY_TYPE:-null}" = "m" ]; then
        DEPLOY_TYPE="mgr"
    else
        echo
        echo "Please Input s or m."
        echo
        return
    fi

    #--- confirm deploy  
    echo
    echo -n "Deploy on $DEPLOY_SERVER of $DEPLOY_TYPE ? (y/n) > "
    read FLG_DEPLOY

    if [ "${FLG_DEPLOY:-null}" = "y" ]; then
        echo ""
    elif [ "${FLG_DEPLOY:-null}" = "n" ]; then
        echo
        echo "Thank you."
        echo
        return
    else
        echo
        echo "Please Input y or n."
        echo
        return
    fi

    #--- confirm commit  
    SSH_AGENT_PS=`ps -e | grep ssh-agent`
    echo $SSH_AGENT_PS
    if [ "${SSH_AGENT_PS:+exist}" = "exist" ]; then
        expect -c "
            set timeout 1
            spawn ssh -l kg_tsubasa $DEPLOY_SERVER 
            expect \"kg_tsubasa@w112:~$ \" 
            send \"deploy -s $DEPLOY_TYPE \n\"
            expect \"Deploy OK?\"
            send \"n\n\"
            send \"exit\n\"
            interact
        "
    elif [ "${SSH_AGENT_PS:-nonexist}" = "nonexist" ]; then
        expect -c "
            set timeout 1
            spawn ssh -l kg_tsubasa $DEPLOY_SERVER
            expect \"Enter passphrase for key '/home/karino/.ssh/id_rsa':\" {
                send \"password\n\"
            }
            expect \"kg_tsubasa@w112:~$ \"
            send \"deploy -s $DEPLOY_TYPE \n\"
            expect \"Deploy OK?\"
            send \"n\n\"
            send \"exit\n\"
            interact
        "
    fi
    echo

ssh-agentが立ち上がっているか否かによって、
条件分岐をしているが、
もう少しうまいやり方がありそうな気がする。

そして、正常終了したか否かのステータスはつけていない・・・。

ssh回りの設定をした時のめも。

【ssh パスワードと公開鍵認証の違い】
sshについて


【ssh RSAとDSAの違い】
SSHでの暗号方式、RSAとDSAの違い


【ssh鍵の生成】
$ ssh-keygen -t rsa
$ cat id_rsa.pub >> $HOME/.ssh/authorized_keys
ssh-keygenによって生成されるファイルが2つ。
id_rsa :秘密鍵
id_rsa.pub :公開鍵

公開鍵のほうを接続先のサーバに設定。


【sshパスフレーズ入力省略】
ssh-agent
① bashrcとかに書く。
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa

※ これだと、ssh接続ごとにパスワードを入力する必要がある。

② keychainを使う。
keychain
「.bash_profile」に下記を書く。
keychain .ssh/id_dsa
. .ssh-agent-${HOSTNAME}


【sshfs】
① パスフレーズ
マウント:$ sshfs karino@server: /home/karino/@server
アンマウント:$ fusermount -u /home/karino/@server

② 公開鍵認証の場合
マウント:$ sshfs -o IdentityFile=/home/karino/.ssh/id_rsa karino@server: /home/karino/@server
アンマウント:$ fusermount -u /home/karino/@server


【sshのkeepalive】
/etc/ssh/ssh_configに、
ServerAliveInterval 120と書く。
これは、120秒毎に、ssh接続先にkeepaliveを飛ばす設定。