mod_rewriteで条件分岐

URLがある条件にマッチした場合にはURLを書き換えたくない場合がある。
そういうときは [S] (Skip) フラグを使用する。
このフラグを使うとURLが条件にマッチした場合にはn行下までの条件をスキップすることができ、擬似的にIF文のような条件分岐を実現できる。このとき、RewriteRuleは以下の様な構文になる。

RewriteRule <condition> - [S=n]
#URLが<condition>にマッチした場合はn行下までの条件をスキップする


Apache公式ドキュメントに書かれていた例が分かりやすかった。

# Does the file exist?
RewriteCond "%{REQUEST_FILENAME}" "!-f"
RewriteCond "%{REQUEST_FILENAME}" "!-d"
# Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza.
RewriteRule ".?" "-" [S=3]

# IF the file exists, then:
    RewriteRule "(.*\.gif)" "images.php?$1"
    RewriteRule "(.*\.html)" "docs.php?$1"
    # Skip past the "else" stanza.
    RewriteRule ".?" "-" [S=1]
# ELSE...
    RewriteRule "(.*)" "404.php?file=$1"
# END
https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_s

Raspberry Pi買ったのでシェルからLチカ

f:id:koki-h:20150913143726j:plain
何年も前から欲しい欲しいと言って買ってなかったRaspberry Piをとうとう購入した。
日経BPのラズパイマガジンとケースのセットで8000円位だったか。
とりあえずOS入れて無線LANの設定やらなんやらを済ませ、SSHでログインしてLチカを試した。
Pythonのライブラリを使えば簡単そうなのだけどなんとなく嫌で以下のサイトを参考にシェルからGPIOを制御する方法を試してみた。tool-lab.com

簡単にまとめると

  • GPIOの各ピンは /sys/class/gpio/ 配下の /sys/class/gpio/gpio*/value (*はピン番号)という仮想ファイルに0または1の値を書き込むことによってOFF(0)、ON(1)を切り替えることができる
  • 上記のファイルは最初は存在していないので以下の方法で作成する必要がある。(OSをシャットダウンすると消えてしまうのでOSを起動するたびに毎回作る。)
$ echo 18 > /sys/class/gpio/export #18番ピン用の仮想ファイルが作成される
  • ファイルを作成するだけでは使用可能にならないので次に入出力を設定する必要がある。(こちらもOSをシャットダウンすると消えてしまうのでOSを起動するたびに毎回設定する。)
$ echo out > /sys/class/gpio/gpio18/direction #18番ピンが出力に設定される
  • あとはechoコマンドを使うなどして0/1を書き込めばOK
$ echo 1 > /sys/class/gpio/gpio18/value #ON
$ echo 0 > /sys/class/gpio/gpio18/value #OFF

上記を応用してrubyでLチカをした

10.times do
  `echo 0 > /sys/class/gpio/gpio18/value`
  sleep 0.5
  `echo 1 > /sys/class/gpio/gpio18/value`
  sleep 0.5
 end

上記をもっと簡単にできるようにしたWiringPiというツールもあるらしいが、また今度調べる。

ちなみにRaspberry PiのGPIOから線を引き出す際には以下の様な延長基板が便利。

私はスイッチサイエンスのキットを購入したがハンダ付けを間違えてブレッドボード側のピンを裏表逆にしてしまった。
私のようなおっちょこちょいの人は完成品の方を購入したほうがいいかもしれない。

便利なライブラリが使えなかったのでrubyからsendmailコマンドを直接叩いて添付ファイル付きメール送信

ruby1.8.5しか入っていないサーバでメール送信するスクリプトを書くことになった。
rubyでメール送信するときはponyを使うと便利なので愛用していたのだけど、ruby1.8.5では最新版が動かない。シンタックスエラーが出まくる。*1
github.com

古いバージョンの中から動くものを探すのもいいかもしれないが、すごい手間が掛かりそう。依存ライブラリも含めてすべてのGemを調べる必要がある。
そんなことをするよりもsystem関数でsendmailコマンドを叩いてやったほうが早いかと思い、以下のスクリプトを書いた。
mime-typeがcsv固定になってたり汎用性は無い。


ほぼ、以下のシェルスクリプトの書き写し。qiita.com

まあ最新の環境が用意できるのが一番いいのだけど。そうもいかない場合もある。こういう基礎は大事だと思った。*2

*1:->記法とか{key:val}記法とか

*2:とはいえ最新のrubyの便利さも思い知らされた。温故知新。文字コードや改行文字の自動変換など本当にうまくやってくれる

WordPressのWordPressアドレスとサイトアドレスを別にすると管理バーが出なくなる。(あるいはWordPressのWordPressアドレスとサイトアドレスを別にしても百害あって一利なしということはもっと拡散されるべき)

百害というか一害なんですけども。field-archive.com
まったくもう。
管理バーが表示されないんですよ。
他の人が作ったサイトを引き継いで、ファイルやらDBやらをまとめて別サーバに移動させ、動作確認してみるとログインしても管理バーが表示されない。

ぐぐってもwp_footer()呼んでないんじゃないのとか、ユーザごとの表示設定間違ってんじゃないのとかログアウトしてログインしなおしたら直るとかそんな情報が大量に出てくる。それくらいもう確認しとるんじゃとやり場のない怒りを抑えつつ検索結果の下位のほうを一つ一つ確認してみたところ上記の記事が見つかりましたよ。この方神ですか。
これを解決するためにいろいろな設定を変更しては試し、を何回も何回も丹念に繰り返したことでしょう。
素晴らしいじゃないですか。
それに比べて「wp_footer()呼べば直りますよ?」とドヤ顔で書いているブログの浅ましさ(すみません言い過ぎです)。

まあそれは置いといて、WordPressWordPressアドレスとサイトアドレスが違っていると(先頭www.の有り無しとか。今回の俺のケースはこれでした。)こんな思わぬところで落とし穴にハマってしまうのでやめといたほうがいいよ。という話でした。
というか設定が2つある理由をよく理解しておくべきなんかな。調べてないけど。

さくらのレンタルサーバに入っているVimでもUTF-8使えるやん。(export LANG=ja_JP.UTF-8 だけで十分だった話)

さくらのレンタルサーバスタンダードプランにSSHログインしてVimを使おうとしたがUTF8なテキストが文字化けしてどうにもよろしくない。
手元のMacに入れてる.vimrcをコピーしてもダメ。
これはイカンとぐぐってみるとさくらのレンタルサーバVimはUTF8が化けるので自分でコンパイルしたという話がぞろぞろ出てきた。
そこで俺もと最新のソースを取ってきてやってみるがそれでもうまくいかない。
どうしたらいいのよ、と頭を抱えたところでターミナルの文字コード設定をEUCにしてみると綺麗に表示できる。
これはサーバのシステムの文字コードEUCになってるんだなと。
ということは、LANG環境変数か。で、export LANG=ja_JP.UTF-8を.bashrcに書いて、ターミナルはUTF8にしてみる。うまくいく。
もしや、これは、と思って、最初から入っているVimでUTF8のテキストを開いたらちゃんと読めるじゃないの。
てなわけでVimコンパイルとかは全く無駄でした。今のさくらのレンタルサーバに入っているVimはちゃんとUTF8が読み書きできるみたいです。
ネットの情報に振り回されて2時間無駄にしました。いやはや。

続・Windowsがシャットダウンするとき、動作中のrubyプログラムはどうなるのか? あるいはシグナルを他プロセスに投げられるとか甘えだし〜

昨日書いた記事の続編。
Windowsがシャットダウンするとき、動作中のrubyプログラムはどうなるのか? - koki-h's diary

Windowsでシグナルってどんなふうに扱われてるのかな、と思ってググってたら以下の記事を見つけた。

そもそも他プロセスにシグナル投げられるとかそんなの甘えだしー。
あ、他プロセスにシグナル投げられるかどうか、ってのはちょっと補足が必要か。
Unixの世界だとシグナルってOSの機能(っていうのかな)の一部だけど、他の世界では単に規格Cに定められた非同期例外処理である。
そして規格Cでは別のプロセスにシグナルを投げることができるなんて一言も言ってないし、僕らのMSVCRTでももちろん自プロセス内にしかシグナルは投げられない(raise(3)関数を参照せよ)。

http://www.garbagecollect.jp/~usa/d/201305a.html#id20130508_P1_4

衝撃の事実。Windows(というかUnix以外)のプロセスは外部からのシグナルを受け取れない。しかし自分の親プロセスからは受け取れる。
なるほど。コマンドプロンプトでCtrl+Cを押した時だけシグナルが捕捉できたのはそのためか‥。
そして俺の期待は甘えだったということが明らかになった。反省しま〜す。(納得いかない表情で)

Windowsがシャットダウンするとき、動作中のrubyプログラムはどうなるのか?

まあ強制終了されるのだけど。
普通、rubyプログラムは外部から強制終了させられるとき(INTシグナルが送られてきた時)はInterrupt例外を吐いて死ぬのだけど、OS自体がシャットダウンするときはどうなるのか?今回はWindows7で確かめてみた。ちなみにRubyruby 2.1.5p273 [i386-mingw32]というのを使った。
こんなプログラムを書いて実験してみた。

  • loop1.rb
while(true) do
  puts "working!"
  sleep 1
end

これを普通にCtrl+Cで強制終了するとまあ、以下のようになる。これは当たり前。

> ruby loop1.rb
working!
working!
working!
loop1.rb:3:in `sleep': Interrupt
  from loop2.rb:3:in `<main>'

今度は実行中にWindowsをシャットダウンしてみる。
シャットダウンした後にもう一度Windowsを立ち上げて実行結果を確かめられるように、標準出力と標準エラー出力をファイルに出すことにした。

> ruby loop1.rb > AAA.TXT 2> BBB.TXT

結果はAAA.TXTもBBB.TXTも空白。なんだそりゃ。
なぜ何も出力されないかを考えてみる。

  1. INTシグナル以外のシグナルが送られて来たことにより強制終了したため、Interrupt例外が発生しなかった。(INT以外のシグナルでも発生するかもしれないけど)
  2. シャットダウンの時は何のシグナルも送ってこず、ただ強制終了させられた。
  3. 何かしらのシグナルが送られてきたが、ruby側で捕捉する間もなく強制終了させられた。

とりあえずシャットダウンの時にシグナルが送られてきて、捕捉されるかどうかだけでも確かめたい。
以下の様なプログラムにしてみた。

  • loop2.rb
trap(:INT) { p "INT";exit }
#trap(:ILL) { p "ILL" }
#trap(:FPE) { p "FPE" }
#trap(:SEGV) { p "SEGV" }
trap(:TERM) { p "TERM";exit }
#trap(:BREAK){ p "BREAK" }
trap(:ABRT) { p "ABRT";exit }
trap(:EXIT) { p "EXIT";exit }

while(true) do
  puts "working!"
  sleep 1
end

リファレンスによれば、WindowsrubyではINT ILL FPE SEGV TERM BREAK ABRT EXITのシグナルが捕捉できる。
http://docs.ruby-lang.org/ja/2.1.0/class/Signal.html
ただし、ILL FPE SEGV BREAKはtrapメソッドの引数に指定すると実行時エラーになるのでコメントにした。
普通に実行してCtrl+Cで強制終了した場合*1は以下の様な出力になる。

> ruby loop2.rb
working!
working!
working!
"INT"
"EXIT"

*2
じゃあさっきと同じようにしてプログラムを起動し、Windowsをシャットダウンしてみる。

> ruby loop2.rb > AAA.TXT 2> BBB.TXT

そして、Windowsを立ち上げてAAA.TXTとBBB.TXTをテキストエディタで開いてみると。。
結果は空白。何にも出力されていなかった。

てなわけでrubyプログラムの実行中にWindowsをシャットダウンした時の動作は、

  • 何のシグナルも送ってこず、ただ強制終了させられる。
  • 何かしらのシグナルが送られるが、ruby側で捕捉する間もなく強制終了させられる。

の2つが濃厚なようです。あと、rubyで捕捉できないシグナルが送られてくる、っていうのも考えられるか。。

追記:2015/3/15
タスクマネージャーから強制終了したらどうなるのか?
気になったので試してみたらシャットダウンの時と同じ動きでした。



以下余談
こんなことを考えたのは、エラーログをなにも吐かずに異常終了したプログラム*3があって、なんとか終了した原因を知りたいというのがありました。やっぱり実行中にPC再起動しちゃったんじゃないかなあ。。WindowsUpdateとかだってあるかもしれんし。という疑いはあるのですが、証拠はありません。
それならOSのシャットダウンをRuby側で捕捉できるようにすれば、動かぬ証拠を記録できるのでは?と考えたのです。しかし結局ダメだった。

*1:本当は強制終了ではなくシグナルを捕捉した上で正常終了する。

*2:最後に”EXIT”が出ているのはINTを捕捉した後、exitメソッドを呼んだことによりEXITシグナルが送られてきたため。

*3:処理が終わるのにすっごく時間がかかる