2009年11月5日木曜日

ssh を使って Linux のあるPCのウィンドウを自分のPCで表示

以前は xauth や xauth 等を利用して、サーバーの許可設定や環境変数 DISPLAY を注意深く設定して、やっとウィンドウを他のPCに取り出すことができました。以前は面倒くさい手順が必要でしたが、最近の Linux では ssh がトンネル化してくれて非常に簡単にできるようになっていますね。

ウィンドウを送りたい端末Aと、ウィンドウを受け取って表示したい端末をBがあるとします。まず、Aの側で ssh サーバーを起動しておきます。Ubuntu の場合、

% sudo apt-get install ssh

でインストールしてくれて、しかもサーバーの自動起動設定もしてくれます。

そしてBの側から、

% ssh -X [Aのユーザー名@AのIPアドレス]

と -X オプションを書いてAにログインすると、そのセッションで開いた X のアプリケーションはBのディスプレイに表示されます。これで、共用の Linux のパソコンがあった場合、誰かが使っていても画面を自分の画面に引き寄せて作業できるようになります。

もちろん、この方法はBの側の X サーバーを利用するので、X サーバーが起動してない Windows の端末エミュレータ等(Tera Term とか Putty)では使えないので気をつけてください。

2009年11月3日火曜日

Ubuntu 9.10 への OpenGL のインストール

Ubuntu 9.10、出ましたね。これに合わせて環境を 9.10 でクリーンインストールし直したので、その時の OpenGL 関係のインストール方法についてまとめておきます。

注意!この記事は古い情報になっています。最新の方法についてはこちらをご覧下さい(リンク先は Ubuntu 10.04 への、となっていますが 9.10 でも適用できると思います)

まず、ビデオカードのドライバを入れます。ビデオカードのベンダーのホームページに行ってドライバをダウンロードし、手順に従ってインストールします。[システム]-[システム管理]-[ハードウェア・ドライバ]あたりからでも入れれるはず。インストール後、

% glxinfo | head

で、次のような一文が見つかるとOK。

direct rendering: Yes

次に、依存関係のファイルをインストール。必要なパッケージは次の通り。

  • OpenGL … libgl1-mesa-dev
  • glut … freeglut3-dev
  • glew(最新・拡張機能を使いたい場合) … libglew1.5-dev
  • その他依存ファイル … libxmu-dev, libxi-dev

インストールは、基本的に apt で自動的にやってくれます。ターミナルを開いて、

% sudo apt-get update
% sudo apt-get install libgl1-mesa-dev freeglut3-dev libglew1.5-dev libxmu-dev libxi-dev

あたりでできるはず。これらの依存関係もインストールしてよいか尋ねられた場合は、もちろんインストール。1回目の sudo コマンドでパスワードを求められるので入力する。

ここまでできたら、こちらの4章に従ってサンプルプログラムを動かしてみましょう。有名な床井先生の入門ページです。あ、もうインストールは全て終わっているので、2章の「GLUT のインストール」は必要ないですよ。

ちなみに床井先生のページの3章のコンパイルコマンドについて、プログラムのソースコードが program.c の時、Ubuntu 9.10 では

% cc program.c -lglut -lGLU -lGL -lXmu -lXi -lXext -lX11 -lm -lpthread

で動くことを確認しています。

ファイルを一括ダウンロード&一括ファイル名編集

最近、ある会員用ページで200曲以上の mp3 データをダウンロードできる権利を手に入れました。ところが、まとめてダウンロードできずに一つ一つリンクが貼ってありました。しかも、そのダウンロードしたファイルが全てローマ字表記で、"hajime.mp3", "tsugi.mp3" といったように非常にわかりにくかった。

番号タイトルファイル名
1始めの曲hajime.mp3
2次の曲tsugi.mp3
3三番目の曲sanbanme.mp3

そこで、データを丸ごとダウンロードし、このダウンロードした mp3 をローマ字じゃなくて全部日本語の曲名のファイル名にしたい、というお話。例えば、「hajime.mp3」は「1-始めの曲.mp3」に、「tsugi.mp3」は「2-次の曲.mp3」に変換といった具合。もし数曲程度なら手動で整理した方が早いけれど、3桁もの数の曲データの手動ダウンロードと手動ファイル名修正はいかがなものかと。

とりあえず、ファイルの一括ダウンロードはすぐにできそうなので、ダウンロードツールを探しました。

あ…会員ページにログインする機能のないダウンロードツールは利用できないんだった。。そこで、Firefox のアドオンで、表示されているコンテンツを丸ごとダウンロードできる DownThemAll をインストールしてデータを一括ダウンロードしました。

ダウンロード設定。しばらく待つと、全部のファイルが無事ダウンロード完了。

さて、次はファイル名編集。幸い、HTML のテーブルの形でデータが整理されてたので、HTMLのソースから該当のテーブル部分を抜き出して、XML パーサにかけたらできそうですね。HTML の元のソースから table タグを見つけて抜き出し、拡張子 XML で保存。

ブラウザで開いてみると…構文エラーが発生。

エラー: invalid attribute value
<td width=5%>

…そうか、XML の構文はかなり厳格で、属性値にダブルクォーテーションがないとか、閉じ括弧があらゆるタグについてないとエラーになるとか、色々あったんですね。HTML 構文はそのあたり適当でもブラウザが適宜解釈してくれるんだけど、XML ではそうは行かない。HTML を XML に変換するのに躓くのは想定外というか、そういうことがあったって忘れてた。

そこで、このあたりを修正できるツールを探していると、Tidy というツールを発見。XML ドキュメントのエラーを探して自動で修正してくれるツールみたいです。早速 Windows 版をインストールして試してみる。

お…文字化けで肝心の日本語を変換できず…。あれこれ他のページを探してみるとこのページを発見!

http://html.idena.jp/program/index.shtml

このツールを使うと、無事に XML 構文が修正されて、XML として読み込むことができました。

ちなみに、Linux にても Tidy は利用できました。文字コードを UTF-8 にしておいて、次のコマンドを使いました。

% tidy -utf8 -asxml input_file > output_file

ただし、この方法で生成した出力ファイルには1つ問題がありました。&nbsp; が存在した場合、これは XML で定義されていないためにこの後使う expat でエラーになるようです。あまり綺麗ではないのですが、結局ストリーミングエディタを使って無理やり矯正してみました。

% sed -e 's/&nbsp;/ /g' output_file2 > out.xml

さて、この XML を構文解析して、ファイル修正スクリプトを組む必要がありますね。XML パーサだったらどこにでもあるだろう。なんとなく、python で作る方法を調べる。xml.parsers.expat あたりが軽量で使いやすそうなことがわかったので、このあたりを使うことにした。

…ソースを載せようと思ったけど、よく考えたら会員じゃない人は試せないわけね。雰囲気だけ載せときます。

#!/usr/bin/python
# coding: utf-8

import sys
import os
import xml.parsers.expat

# XMLファイルをパース
def parseDocument(p, file):
    f = open(file, 'r')
    p.ParseFile(f) 
    f.close()

# 要素の開始(<td> とかのときに呼ばれる。attrs には td の属性値)
def start_element(name, attrs):
    # if name == 'td': とかの処理

# 要素の終了(</td> とかのときに呼ばれる)
def end_element(name):
    # if name == 'td': とかの処理

def char_data(data):
    # data に値が入る

# パーサの作成
p = xml.parsers.expat.ParserCreate()

# ハンドラの設定
p.StartElementHandler = start_element
p.EndElementHandler = end_element
p.CharacterDataHandler = char_data

# table.xmlをパース
parseDocument(p, 'table_new.xml')

ここまで結構長かった。。

[XREA] 携帯サイトへリダイレクト

RewriteEngine を使って、携帯からのアクセスがあった場合に携帯ページへリダイレクトするコードを作ってみました。
XREA/Coreserver で動作を確認しています。

http://foo.bar/

がトップページで

http://foo.bar/mobile/

が携帯サイトだった場合、ドキュメントルートの .htaccess に以下のコードを記述。

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} (DoCoMo|Vodafone|J-PHONE|SoftBank|UP\.Browser|KDDI)
RewriteCond %{REQUEST_URI} !^/mobile/
RewriteRule ^(.*) http://foo.bar/mobile/ [L]

4行目で、携帯からのアクセスならあらゆる場合に /mobile/ に飛ぶようにしてますが/mobile/ の中にいる場合も /mobile/ に飛ぶと /mobile/ トップページに常に縛られるので、既に /mobile/ の中にいた場合だけ /mobile/ トップページに飛ぶのを除外するコードが3行目の !^/mobile/ です。
モバイルモバイル!

現在のところ上手く動いてる。ただ、ルートに置くと他の全ページに影響するんでバグがあった場合ちょっと怖いですね。

source コマンドではまった

親シェルから呼び出された子シェルで export された環境変数は、呼び出し元の親シェルでは反映されない。つまり、子シェルで環境変数を設定しても、親シェルに戻った瞬間にその環境変数の設定は失われるということ。

別のスクリプトに書かれた環境変数の export を呼び出し元にも反映したいなら、そのスクリプトを子シェルで実行するのではなく、include と同じ意味を持つ source か . を利用して呼び出し元に取り込まないといけない。これだと、子シェルを作らず、親シェル上で実行される扱いになるので、別スクリプトの export が呼び出し元にも反映されるわけです。

で、その source コマンドで嵌りました。

最近の Ubuntu は dash という sh 拡張のシェルを基本にしているらしく、以前に作ってた bash スクリプトを動かすと source コマンドが存在しないエラーが発生。

ネットで調べてみると、source と . は等価変換可能、ということだったので bash で書かれた source を全て . に変換。

でも、これが上手く動作しない。

実は、bash 用コード中に

% source prog param

なんて無理やり source で呼び出したコマンド(prog)にパラメータ(param)を指定してて、bash 上ではこれでうまく行ってたんですが、

% . prog param

ってやってみたら、param が付いてこないみたい。親シェルの引数がそのまま prog に引き継がれるよ…。

どうやら source コマンドの後ろの引数の部分の仕様は未定義らしくて、実装によってその挙動が異なるみたいです。今まで使ってた bash では、引数処理まできちんとやってくれてたけど、どこでも動くわけではなかったみたい。

結局のところ、dash ではどうしても無理そうだったので

% arg=123
% . myscript

として myscript 内で変数 arg を評価するコードに…。これを見てアセンブラの push を思い出しました。しかも、このスクリプトは共有されてて今まで通り bash から読み込まれることもあるので、arg の存在の有無を判定して、無さそうなら引数を確認…とかかなり複雑に。なんか汚い…。

…まぁ、これで動作するようになったので動かないことはなくてほっとしたけどね。