2009年11月21日土曜日

NetWalkerでシェルスクリプトから通知してみるPythonとかで


今日は三連休初日な訳ですが、みなさんいかがお過ごしでしょうか。
気がつけばもう夕方ですか。私は雨戸も開けずに引きこもっております。外の天気を知らないどころか、外の光も見てないです。あ、タイトルからググってきたスキップさんはこちらのリンクで文中にジャンプ可です。

でも今日ちょっと軽い地震の揺れがありましたね。Twitterでは「東京では揺れなかった」と言っていた人が居ましたが、私は多摩の外れ一応東京で何故か揺れに気づくことができました。例え引きこもっていても、その一点だけは認識が世界(いや関東地方?ニュースも見てないや)に開かれていたのです。それに、今ブログを打っているのもNetWalkerですので、例え引きこもってはいても上半身だけモバイラーな感じです。よし、家庭内無線LAN止めてイー・モバイルでつないどくか。ついでにACアダプタも抜いて...いや、それは止めとこう。画面が暗くなるしな。
それで引きこもって何をやっていたのかというと、NetWalkerの通信の設定で色々実験をやっておりました。結果は見事失敗。全然うまくいきません上手く行ったらブログに書こう成功のイメージ無いけど。
さて、そこで本日のブログのお題なんですが、その失敗の成果を大々的に紹介したいと思います。
失敗の成果なので達成感ゼロです。途中で使ったTipsのみ紹介。
そういえば、来週私の関わっているシステムの立ち上げがあるんですが、なんかうまくいく気が全然しません。あ、関係の方はここ見ないでね。あと、職場の人はこれ見てたら○○さんヤバいらしいと噂広めて下さい。よろしく。

所で以前も書いたか書いてないか良く憶えて居ませんが、NetWalkerで端末(コマンドプロンプト)で作業していると、どうも背中が丸まって良くないですね。やっていることはコマンド打ったりバッチファイル(linuxではシェルスクリプト)実行したりとかでも、なるべくふんぞり返ってぬるい感じで操作したいものです。性格とかもあるかもしれません。私は曲がり角とかで車のボンネットが大きく回る感じが好きで(だから、ボンネット遠くに有った方がいい)、運転席が後部座席にあるみたいな車があったら一度運転したいと思っているのですが、逆にミニとか好きな人も居る訳ですし。
いや、外出してないと良くないな。なるべくインナースペースに行かないように進めないと。
そんな訳でやっぱり端末内だけの操作というと、やはり何か気持ちの余裕見たいなものがないですね。

それで本日ぜひご紹介したいのは、シェルスクリプト(Windowsでは、いやWindowsでもコマンドスクリプト、広い意味でシェルスクリプトなんですが、みんなバッチファイルと言いますよね)、シェルスクリプトの中からGUIで通知をする簡単な方法です。
冒頭の画像がそれです。なぜか通知が2種類出ていますがそれは追って。

ここでスキップさんこんにちは。あれ?意外と無駄話が短かったな。まぁそういう事もあるよね。
今回のサンプルですが、接続状態を調べてGUI通知で表示するというシェルスクリプトになっております。サンプルなので、実用性は(社交辞令的に表現しても)微妙という他はない感じですが、何かの時に使う機会があるかも知れません。例えば、端末の文字だけの通知だと、新システムのデモ説明会で居眠り率が50%越えてしまって後でプロジェクトメンバーの会話が微妙な感じになるとか。いや、無いですね。ないない。でもせっかくなので続けます。

まず先にifconfigの説明しとこう。
端末でifconfigを実行すると、以下の様に接続情報が表示されます(中は読む必要無いですよ)

XXX@XXX:~/sh$ifconfig
eth0 Link encap:イーサネット ハードウェアアドレス XX:XX:XX:XX:XX:XX
inetアドレス:192.168.0.6 ブロードキャスト:192.168.0.255 マスク:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1
RXパケット:81 エラー:14 損失:0 オーバラン:0 フレーム:0
TXパケット:102 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:41606 (41.6 KB) TXバイト:28894 (28.8 KB)

lo Link encap:ローカルループバック
inetアドレス:127.0.0.1 マスク:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 メトリック:1
RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:0 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:0
RXバイト:0 (0.0 B) TXバイト:0 (0.0 B)

ppp0 Link encap:Point-to-Pointプロトコル
inetアドレス:XXX.XX.XX.XX P-t-P:XX.XX.XX.XX マスク:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 メトリック:1
RXパケット:92 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:92 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:3
RXバイト:5028 (5.0 KB) TXバイト:4219 (4.2 KB)


eth0は無線LAN loはローカルだから関係なし ppp0はppp接続です。接続していないと出ません。上でppp0とeth0が両方出てるのは実際両方つないでいるからです。
今回、接続状況を表示するシェルスクリプトを作成しますので、ifconfigを実行して、行の先頭にethがあったら無線LAN接続中 行の先頭にpppがあったらppp接続中とみなす事にします。あくまで通知がメインなのでスルーよろしく。

サンプルはこんな感じです。

#!/bin/sh


if ifconfig | grep "^ppp" >/dev/null
then
python -c "import pynotify;pynotify.init('PPP');n=pynotify.Notification('PPP','接続中です','dialog-info');n.show()"
zenity --info --timeout=3 --text "PPP接続中です"
elif ifconfig | grep "^eth" >/dev/null
then
python -c "import pynotify;pynotify.init('eth');n=pynotify.Notification('イーサネット','接続中です','dialog-info');n.show()"
zenity --info --timeout=3 --text "イーサネット接続中です"
else
python -c "import pynotify;pynotify.init('none');n=pynotify.Notification('無接続','接続中していません','dialog-info');n.show()"
zenity --info --timeout=3 --text "接続していません"
fi

(注:右が切れている場合は選択してコピーすると端まで取得できます)
windowsな人のために実行方法を説明します。
例としてホームフォルダの下にshというサブフォルダを作ってpppnotify.shという名前で置くとして、
geditに上のサンプルを貼って、/home/ユーザー名/sh/pppnotify.sh で保存します。
端末で、/home/ユーザー名/shフォルダに移動(cd shで)して、chmod 755 pppnotify.shで実行属性を憑けます。
ところで、$chmod 755 pまで打ってTAB押すと補完で$chmod 755 pppnotify.shまで自動で入るの知ってた?
さて、
./pppnotify.sh で実行です。unixはwindowsと違ってカレントディレクトリが実行パスに入らないので./が要ります。
あと、余談ですが、テストで実行するとき、いちいちchmod 755するのめんどいですね。その場合は、
sh pppnotify.sh で実行すれば、データファイルのままでも実行できますよ。

それではプログラムの説明です。と言っても私はwindowsの人なので、bashシェルの謎の文法には詳しく有りませんので、ちゃんと知りたい人は詳しそうな人も当たって下さいね。

まず全体の制御構造から。

if 実行文1
then
 実行文1の終了ステータスが0の時実行される
elif 実行文2
then
 実行文2の終了ステータスが0の時実行される
else
 それ以外の時実行される
fi

終了コードはwindowsの人もお馴染みですよね。コマンドを実行するとwindowsのバッチではerrorlevelという変数に終了コードが代入されてきますが、unixのシェルでは$?という変数に結果が代入されてきます。ここでは$?使ってませんが。さて、ifの後ろが式でなくて実行コマンドなのが変態的ですね。まぁ終了ステータスを返すので,ある意味式と言えなくもないですが。ここでは使っていませんがifに式を書く場合は、if [式] と[]で囲みます。分かりにくいですね。

次はifの実行文1になってるifconfig | grep "^ppp"ですが、これはwindowsの人でもお馴染みですね。ただしおっさん限定かな、windowsの場合(ってかDOS)。|はパイプ記号で、ifconfigコマンドの実行結果(標準出力)を、grepコマンド(の標準入力)に渡します。grepは超有名な検索コマンドで、"^ppp"つまり行の先頭がpppにマッチする行を探します(わからん人は正規表現でGoogle先生に!)。ここでは検索が失敗したか成功したかでセットされる終了ステータスが必要なので、検索結果自体は不要です。
よってifconfig | grep "^ppp" >/dev/nullと標準出力をNULLデバイスにリダイレクト(>)して捨ててます。>/dev/null付けなくても検索結果が無駄に表示されるだけで実害はないですが。
ところで、処理フローとしてpppとイーサ両方あると、pppしか通知出ないですね。まぁあくまで通知がメインなのでスルーよろしく。直すと変数の説明が必要になっちゃうから...

さて、ここから本題ですかね。

python -c "import pynotify;pynotify.init('PPP');n=pynotify.Notification('PPP','接続中です','dialog-info');n.show()"

(注:右が切れている場合は選択してコピーすると端まで取得できます)
これで、右上の通知が出ます。pythonの一行プログラム(ワンライナー コマンド実行で直接プログラムまで書いちゃう)ですね。読みにくい! と思ったら行区切りの;とこで改行すればなんとなくプログラムに見えると思います。
本当はpythonを使わなくてもnotify-sendというコマンドで通知できるらしいのですが、netwalkerでは初期状態でインストールされていない様なので、ここはバッテリーインクルードのpythonで。
最初のpynotify.sampleは多分何でもよし(知ってる人教えて!)pynotify.init('PPP')のPPPはタイトルの様ですが、表示されないので何でも良いようです。後ろの"PPP" "接続中です"書き換えれば何でも表示できます。タイトル(ここではPPP)は空文字列だとエラーでる様です。'dialog-info'はアイコンの種類?infoで電球、"dialog-warning"でびっくり三角、パラメータ省略するとアイコン無しになります。
ところで、この標準の通知は、なんか色々やってるウチに出なくなる事があるんだよね。やりかた間違ってるのかも知れないけど、ネットでも通知のトラブルが結構引っかかる。

そこで、念のためもう一個の方法を紹介します。サンプルでは両方入れちゃってるけど。コメントアウトは行頭#で。


zenity --info --timeout=3 --text "PPP接続中です"

こちらは、単純にポップアップダイアログが出ます。タイムアウトが指定できるので通知としても良さげ。
zenity --help-allで日本語のヘルプも出る。入力とかも出きるらしい。なぜか最初から入ってた便利やつ。

と、色々通知で苦労してた訳ですが、実はスリープとか復帰とかのスクリプトで色々通知したいなと思って、色々やってた訳なんですよ。ところが、そっちのスクリプトでは画面への表示が何にも起こらず、夢敗れる。
いや、スリープ復帰の時にあんな事やこんな事や、はたまた○○な事を通知しまくって見たかったのに...今日一日引きこもり損かよ...

と、しかし多分今日は何にもやってなくても引きこもってたと思います。その方がダメージでかいよね。オーライ。

2009.11.22追記です。
出かける前に自分の投稿をつらつら眺めていて気づいたんですが(みなさんはみませんか?私は見ます。結構何度も。)、気づいたんですがいっぺん変数nに代入しない方がよりワンライナーですよね。こんな感じで。
python -c "import pynotify;pynotify.init('Title');pynotify.Notification('タイトル','今日は').show()"
普段"."でどんどんつなげてく習慣の無い人には読みづらいかも知れませんが。

追記です
最初、google先生で最初に出るココのブログ崩壊現実-全てはvirtualに収束する見てサンプル作りましたが(ブログ主さんありがとう)、こっちのgnome.orgドメインの見て書き直しました。なぜかトップページにサンプルだけ貼ってあってpynotifyの説明とか見当たらず。だれか知ってたら教えて。pynotifyのAPIのドキュメントとか。

0 件のコメント:

コメントを投稿