« 2008年11月 | トップページ | 2009年5月 »

2008年12月

2008.12.09

シェルスクリプト・トレーニング 第12回:getopts

シェルスクリプト・トレーニング 第12回
getoptsでスクリプトのオプションを処理する
http://www.techworld.jp/channels/desktop/102774/

公開されました。

|

2008.12.03

Dynamic DO!.jp(無料用)のIPアドレスを変更するシェルスクリプト

本体は1行。処理結果はddnsupdateresult.txtに保存(curl -o ファイル名)。

#! /bin/bash
curl -s -o ddnsupdateresult.txt "http://free.ddo.jp/dnsupdate.php?dn=XXXXXXXX&ip=$(curl -s http://info.ddo.jp/remote_addr.php | cut -s -d: -f2)&pw=XXXXXXXX"

やっていないけど1:
ddnsupdateresult.txtに「FAIL:」という文字列が出力されていたらエラー、「SUCCESS:」という文字が出力されていたら成功、という判定でいいんじゃなかろうか。

やっていないけど2:
curlコマンドがない場合、wgetコマンドでも同じようなことができるはず(結果を標準出力に出すには、ファイル名として「-」を指定、つまり「wget -O - "http://……"」で良いはず)。

私は、とりあえず結果を画面に出力させようと思ったので、curlの-oオプションを外し、iconvで文字コードを変換してsedでタグを除去。

#! /bin/bash
curl -s "http://free.ddo.jp/dnsupdate.php?dn=XXXXXXXX&ip=$(curl -s http://info.ddo.jp/remote_addr.php | cut -s -d: -f2)&pw=XXXXXXXX" | iconv -f eucJP -t UTF8 | sed "s/<[^>]*>//g;/^$/d"

プロセス

1.IPアドレス更新には、ドメイン名とパスワードの他に現在のグローバルIPアドレスが必要
2.Dynamic DO!.jpでは「http://info.ddo.jp/remote_addr.php」でグローバルIPアドレスが取得できるようにしてくれているようだ

コマンドラインで実行してみる(以下ずっとコマンドライン)。

curl http://info.ddo.jp/remote_addr.php

curlの処理ステイタスが表示されるのを避けるためのオプションを探す(curl --help)。-sオプションだとわかった。

実行。

curl -s http://info.ddo.jp/remote_addr.php

結果、どうやら「改行」「REMOTE_ADDR:125.xxx.xxx.xxx」と出力されている。欲しいのは「125.xxx.xxx.xxx」部分。

考えたこと:
1.「REMOTE_ADDR:125.xxx.xxx.xxx」の行の「:」以降だけ出力するフィルタを作ろう
2. cutコマンドで、フィールド区切りを「:」にして(-d:)、2番目のフィールドを出力すればよいだろう(-f2
3.空の行は出力しないようにするオプションを「man cut」で探す。こういうオプションは大抵あるはず→-sオプションとわかった

試してみる。

curl -s http://info.ddo.jp/remote_addr.php | cut -s -d: -f2

無事「125.xxx.xxx.xxx」が出力されたようなので、「curl "http://free.ddo.jp/dnsupdate.php?dn=ドメイン名&ip=IPアドレス&pw=パスワード"」を開くことにする。

「IPアドレス」部分をさっきの「curl … | cut …」の結果と置き換えるために、「$()」を使うことにする。具体的には、「$(curl … | cut …)」のように$(と)の間にそのまま入れる。
(環境変数に保存しておけば別の用途にも便利かなと思ったけど使いたいと思ったことがほとんどなかったのでやめた)

curl -s "http://free.ddo.jp/dnsupdate.php?dn=XXXXXXXX&ip=$(curl -s http://info.ddo.jp/remote_addr.php | cut -s -d: -f2)&pw=XXXXXXXX"

試してみる。

文字化けしているけどSUCCESS:という表示があるのでおそらく成功(curl -s -o ファイル名 "http://…"で結果をファイルに出力して確認可能)。

メッセージがおそらく日本語EUCで出力されており、UTF-8にすればTerminalでも化けずに表示されるだろうから、iconvで変換(iconv -f eucjp -t utf8)してみよう。

curl -s "http://free.ddo.jp/dnsupdate.php?dn=XXXXXXXX&ip=$(curl -s http://info.ddo.jp/remote_addr.php | cut -s -d: -f2)&pw=XXXXXXXX" | iconv -f eucjp -t utf8

OK。
なんとなく、出力結果からタグ(<〜>)を除去したくなる。

安直にやるとこう。

sed "s/<.*>//"

sedは最長一致なので、タグとタグに挟まれた部分(<xxx>〜</xxx>)もきれいさっぱりなくなっていて、なんとなく結果オーライな気がしてしまったが、blogに書くので最短一致になるよう修正。

sed "s/<[^>]*>//g"

最初にやった正規表現:
<.*>は、「<という文字、任意の1文字、←その0回以上の繰り返し、>という文字」となっている箇所にマッチする。<a>でも<aaa>でも<aaa<aaa>aaa>でもマッチする。
「<aaa<aaa>aaa>」は「<aaa<aaa>」でも「<aaa<aaa>aaa>」でも条件に合う。この場合、できるだけ長いパターンが採用される(これが最長一致)。

2つめの正規表現(<[^>]*>):
[^>]は、「>という文字以外」という意味
[^>]*は、「>という文字以外、←その0回以上の繰り返し」という意味
したがって、<[^>]*>は、「<という文字、>という文字以外、←その0回以上の繰り返し、>という文字」となっている箇所にマッチする。
先ほどの<aaa<aaa>aaa>の場合、1つめの>が登場した地点(<aaa<aaa>)でパターンから外れる。結果、最短一致になる(一番短くなるパターンが採用されるのが最短一致)
※sedは最短一致と最長一致を指定し分ける正規表現やオプションが使用できない

1行の中に「<ほにゃらら>」が何回も登場するので、s///ではなくs///で置き換えるようにする。gは複数回適用させる、という意味(gがついていないと、1回置き換えたら終了し次の行に処理が移ることになる)。

gがないとこうなる。


せっかくなので、空行を除去したくなった。
空行は「^$」で表すことができる。^は行頭、$は行末、つまり^$は行頭のあとすぐ行末になってる行すなわち空行に一致。
^$というパターンに一致する行(「/^$/」と表現)を削除(d)。この処理を、先ほどの「s///g」の後ろにくっつける。区切り文字は「;」。

sed "s/<[^>]*>//g;/^$/d"


さらなる細工をしようと思った場合
・タグの間に改行があるとうまく除去できない(いったん改行をとっぱらってから置き換え処理、というのが簡単)
・空行じゃなくて空白文字だけの行どうしたい?(残して良いような気もするし、削除しても良い気もするし)
・<br>を改行に置き換えたくなる
・っていうかSUCCESSかFAILの部分だけ表示すればよくね? ← これだ

じゃぁ今までのsed部分を全部忘れて、
まずはSUCCESSについて

sed -n "s/^SUCCESS:.*/SUCCESS/p"

「行頭にSUCCESS:という文字列」、「任意の文字とその0回以上の繰り返し」に合致する行でSUCCESSと出力(p)、それ以外の行は出力しない(-nオプション)。FAILDも同様に書いてくっつける。

sed -n "s/^SUCCESS:.*/SUCCESS/p;s/^FAIL:.*/FAIL/p"

実行してみる。

#気づいたこと

Mac OS X 10.5.5 に収録されているsedコマンドは、正規表現の¥|(または、の意)に対応していない。↓バージョン3.02(コマンド名sed302)との比較画面


sed302は、以前、OSX収録版のsedコマンドで日本語処理が微妙におかしかった時、Ver3.02のソースをダウンロードしてコンパイルしたもの。念のため普段はオリジナル版を使うようにしようと思いsed302という名前にしておいた。

|

« 2008年11月 | トップページ | 2009年5月 »