ラベル Script の投稿を表示しています。 すべての投稿を表示
ラベル Script の投稿を表示しています。 すべての投稿を表示

2013年10月15日

Python でアクセスログを TSV に変換する

Apache のアクセスログを TSV 形式 (or LTSV) に変換するスクリプトが欲しかったので書いてみました。

用途としては、 grep や awk の組み合わせでは面倒だけれども、 Flume や Fluentd などをインストールする規模でもないサーバーを想定しています。 ちょっとした開発用のサーバーや、社内サーバーのアクセス状況を見るには十分かな、と思います。

2012年12月6日

Python パッケージを作ってみた (clitool)

似たような処理を書く機会が増えてきましたので、Python のパッケージを作ってみました。

Unix 系のツールのお作法として、次のようなルールがあると思います。

  • 引数でファイルのパスを複数与えられた場合は、それらを連続して処理する
  • 引数が無い場合は標準入力から読み込む

grep, sed, awk, sort などはこれらの挙動をしますので、 パイプライン処理を簡単に実現できます。

上記の条件に沿ったコードを書くこと自体は難しくないと思いますが、 存在しないファイルが指定されたときにどうするか? 入力テキストの文字エンコーディングを指定したときにどうするか? ログ出力のレベルをどうするか? といったことを考え始めると、 それはそれで煩雑になっていくと思います。 1週間に2回以上もそんなことを考えているとうんざりするでしょうし、 そういったエラー処理を考慮しないスクリプトを運用するのも大変でしょう。

上記のパッケージを使うと、Python を素のまま使うよりは簡単に記述できると思います。 Python 2.7 と Python 3.3 で動かせるように書いているつもりです。

この記事ではパッケージの導入方法と簡単なスクリプトを紹介してみたいと思います。

2012年11月6日

Python の argparse モジュールを使う

Python の引数処理モジュールである argparse を使ってみます。 そろそろ Python 3.3 で作業を始めるべきでしょうし、いつまでも Python 2.4 のことを考えていても窮屈なためです。

Python の標準ライブラリを使った引数処理には、次のような段階があると思います。

  • sys.argv を使った原始的な方法
  • getopt モジュールを使った Unix 系の伝統的な方法
  • optparse モジュールを使った Python 2.4 などもターゲットにした方法
  • argparse モジュールを使った最近の方法

Argparse Tutorial には次のように記載されています。

There’s two other modules that fulfill the same task, namely getopt (an equivalent for getopt() from the C language) and the deprecated optparse. Note also that argparse is based on optparse, and therefore very similar in terms of usage.

ざっくり日本語訳 :

同じタスクを満足にこなすためには他にも2つのモジュールがあります。 C 言語の getopt() と等価な getopt と、非推奨になった optparse です。 argparse は optparse をベースにしていますので、使い方は非常に似ています。

その他にもサードパーティのライブラリを使う方法があります。 何らかのフレームワークに付随するものや gflags を使う方法はこちらの記事で少しずつ触れています。

"There should be one-- and preferably only one --obvious way to do it." (* Zen of Python) という精神の通りにはいきませんが、 やはり標準ライブラリに沿って実装する方法を身につけておくことは大切だと思いますので、 argparse を使います。

2012年9月16日

pyconjp で発表してきた #pyconjp

Python Conference Japan 2012 で機会を頂けたので発表してきました。 45分枠で70名くらいの方にご参加頂きました。

資料は Google Docs で作成してあり、プレゼンテーションは YouTube にアップされています。 プレゼンの終わりの方でノートパソコンが不調になってしまって5分くらい止まってしまい、せっかく聞きにきて頂いた方には申し訳ない感じです。 また機会があれば、もうちょっとちゃんと準備しておきたいと思います。。。

2012年6月15日

"csvsql" を使って郵便番号データをデータベースに入れる

"csvkit" には csvsql というコマンドラインツールが付属しています。 オプションを調整するとデータを登録できます。

データベースに付属するツールで CSV を登録することもできますが、 複数のデータベースを切り替えて利用したい場合、 O/R マッパーを使って SQL を隠蔽しておくと便利なこともあります。 "csvkit" は SQLAlchemy を利用できますので、データベース接続文字列を切り替えることで ツールの接続先を変更できます。

そこで、実際に SQLite と MySQL に郵便番号データを登録してみます。

2012年6月13日

csvkit を使ってみる

"csvkit" は CSV ファイルの処理や変換のためのユーティリティ群です。 Python で記述されており、コマンドラインスクリプトとして利用する方法と、 Python のモジュールとして利用する方法があります。

ソースコードのリポジトリとドキュメントはこちらにあります。

2011年11月26日

KML ファイルを作成する

ちょっと、CSV のデータから KML ファイルを作成してみます。

2011年8月16日

Waf から Solr を起動させる

Waf を使うと、Python で色々な処理を記述できます。 Waf は普通は C 言語などのコンパイルに使いますが、 ある条件に従って何らかの処理を実行できると便利ですので、他のことにも流用してみます。 以前に、Solr をダウンロードして解凍できることを確認しましたので、 今回は、そこから Solr を起動させます。

2011年8月14日

Indexed Database API を使ってみる

たまには Web 系技術もキャッチアップした方が良いかな、と思っていたら、 Indexed Database API のサンプルがありましたので模写しました。

2011年8月12日

docutils でブログ記事作成

ブログの記事は reST (reStructuredText) で書いて HTML に変換していますが、 パソコンを買い替えたので環境を移行しなければなりません。 ということで、メモを書いておきます。

2011年4月25日

Haskell 手習い

「ふつうの Haskell プログラミング」をつらっと読んで Haskell を書いてみたメモです。 Haskell のメリットとこの本を読む目的は書籍の 9 ページにざっくりとまとめられています。

遅延評価とは、引数を必要なときだけ評価するという、ただそれだけのことです。 それだけのことですが、それがどういう意味を持つかは、実際に体験してみないとよくわかりません。 ある意味、本書は遅延評価の嬉しさを書くためにあると言ってもよいでしょう。

注力すべきことだけを記述するため、余計なことは極力排除し、扱う問題をできるかぎり細分化していきます。 分割統治の「分割」を徹底的にこだわるイメージでしょうか。 書籍の後半では、Haskell のつまずきポイントである「モナド」について「床下配線」と表現しています。 関係ないことはまとめてどこかに押し込める、という雰囲気が分かりやすいですね。

書籍を離れてみると、Haskell とは関数型言語で云々かんぬん... という話もぽつぽつありますが、 個人的には次の一文がもっともしっくりくるまとめでした。

"Haskell は簡単なことと難しいことが入れ替わったような言語で..." / Haskell とは http://www.shido.info/hs/haskell1.html

構文や使い方、それぞれの概念は書籍を読むとして、ここでは簡単なプログラムを書いてみます。 まずは実行環境を整えて、日本語を扱えるようにします。

実行環境と日本語入出を準備する

次の2つの記事を参考にして環境を準備しました。 手元の環境は Mac OSX 10.5 です (ちょっと古いので買い替えようかな)。

macports からインストールします。 おそらく他のパッケージ管理システムでも類似のパッケージが存在すると思います。

$ sudo port install ghc
$ sudo port install hs-utf8-string

ghc-pkg でパッケージ一覧を表示させてみます。

$ ghc-pkg list
/opt/local/lib/ghc-6.10.4/./package.conf:
    Cabal-1.6.0.3, HUnit-1.2.0.3, QuickCheck-1.2.0.0, array-0.2.0.0,
    base-3.0.3.1, base-4.1.0.0, bytestring-0.9.1.4, containers-0.2.0.1,
    directory-1.0.0.3, (dph-base-0.3), (dph-par-0.3),
    (dph-prim-interface-0.3), (dph-prim-par-0.3), (dph-prim-seq-0.3),
    (dph-seq-0.3), extensible-exceptions-0.1.1.0, filepath-1.1.0.2,
    (ghc-6.10.4), ghc-prim-0.1.0.0, haddock-2.4.2, haskell-src-1.0.1.3,
    haskell98-1.0.1.0, hpc-0.5.0.3, html-1.0.1.2, integer-0.1.0.1,
    mtl-1.1.0.2, network-2.2.1.2, old-locale-1.0.0.1, old-time-1.0.0.2,
    packedstring-0.1.0.1, parallel-1.1.0.1, parsec-2.1.0.1,
    pretty-1.0.1.0, process-1.0.1.1, random-1.0.0.1,
    regex-base-0.72.0.2, regex-compat-0.71.0.1, regex-posix-0.72.0.3,
    rts-1.0, stm-2.1.1.2, syb-0.1.0.1, template-haskell-2.3.0.1,
    time-1.1.4, unix-2.3.2.0, utf8-string-0.3.5, xhtml-3000.2.0.1

色々ありますが、最後の一行に utf8-string を確認できます。 インタープリタを起動して Prelude を確認できれば良いと思います。

$ ghci
GHCi, version 6.10.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude>

CSV っぽいファイルの特定パターンを置換する

実際に Haskell プログラムを書いてみます。 ここでは、カンマで区切られたテキストファイルにおいて、 フィールドが「味スタ」の場合に「味の素スタジアム」に変換するものを作ります。 正確な表現ではありませんが、実現したいことは次のことです。

  1. 標準入力から文字列を読み込む。
  2. 一行ごとに区切って、何か処理して、行ごとに改行して出力する。
  3. 何かの処理とは、カンマで文字列を区切って、特定パターンを置換すること。
  4. 特定パターンとは、「味スタ」を「味の素スタジアム」に置換すること。 同じ要領でパターンを追加できると嬉しい。
  5. 置換が終わったら、カンマで連結して一行の文字列に戻す。
  6. 結果を標準出力に書き出す。

そもそも "CSV" とは何か?という問題には深入りしません。 RFC4180 とエクセルの互換性とか、ロケールがフランスなどの場合には小数点がカンマだから云々かんぬん... という話に立ち入ってしまうと大変なので、上述の仕様に簡略化しました。 ダブルクォーテションでの引用やエスケープ、区切り文字以外の用途でのカンマは存在しないものとします。 フィールドの中に改行も許しません。

なお、Haskell で CSV をきちんと扱う場合にはこちらが参考になるでしょう。 Parsec を使います。

ということで、実装してみました。 たぶんもっと効率的な書き方があると思いますが、一番最初はこんな感じで力尽きました。 組み込み関数 (or Prelude で定義されているもの) をもう少し調べた方が良さそうです。

import qualified System.IO.UTF8 as U

main = do cs <- U.getContents
          U.putStr $ unlines $ parse $ lines cs

parse :: [String] -> [String]
parse ss = map replace ss

replace :: String -> String
replace cs = join $ map rewrite $ split cs

split :: String -> [String]
split cs = words $ map csv2tsv cs
  where
    csv2tsv :: Char -> Char
    csv2tsv ',' = '\t'
    csv2tsv c = c

join :: [String] -> String
join ss = map space2csv $ unwords ss
  where
    space2csv :: Char -> Char
    space2csv ' ' = ','
    space2csv c = c

rewrite :: String -> String
rewrite "味スタ" = "味の素スタジアム"
rewrite cs = cs

終わりに

Haskell の入門書を読みながら簡単な入出力のプログラムを書いてみました。 扱っているデータ型がどのデータ型のリストなのか、ということを理解するまでに時間がかかりました。 しかし、ひとつひとつの関数の型を書き下していけば理解できそうであることも分かりましたので、 日常的に書き続けるかどうかの問題とも言えます。

冒頭の書籍の「ふつうのまえがき」でも述べられているように、今、Haskell (もしくはその他の関数型言語) を学ぶ意義は、 異なる知見を得るためという部分が大きいと思います。

本書が目指すのは、Haskell という未知の言語の血を導入することでみなさんにプログラマとしてレベルアップしてもらうことです。 たとえ同じ言語を使い続けるとしても、Haskell の知見を活かせばプログラムはよりよくなるでしょう。 それこそが新しい言語を学ぶことの利益であり、また本書の狙いでもあるのです。

もちろん業務でゴリゴリと使っている人もたくさんいると思いますが、まだまだ「多数派」ではないのかな、と。

その他

2011年3月26日

Python でコマンドラインオプションを扱う方法

コマンドライン引数の扱い方にはいくつかの方法がありますのでメモしておきます。 もちろん sys.argv を自前で解析すれば何とでもなりますが、その解析を頑張りたくはありませんね、という動機です。

  • 標準ライブラリ
  • フレームワークに特有の方法 - Django, Twisted, Tornado
  • 独立したライブラリ - gflags

2010年11月26日

AIR アプリのパッケージング

AIR 2.5 は Android 2.2 (Froyo) に対応するようになりました。 データを失いながらもバージョンアップした手元の Xperia は未だに 2.1 ですが、いつかは 2.2 になると思います。 そんな未来に備えて AIR アプリを作れる環境を整えておきます。

実機で AIR を動かせる携帯端末を持っていませんので、まずは HTML+JavaScript+CSS で普通のデスクトップアプリを作ることにします。 AIR アプリを作る場合には Flash もしくは Flex で ActionScript も使えますが、 XML (MXML) の中にスクリプトを書くのは苦手なので JavaScript にします。 こちらの方法で実装しておくと、通常の Web アプリケーションや Chrome 拡張などを流用できるかもしれない、という淡い期待もあります。

セットアップ

Adobe のサイトが非常に整備されていますので、通常のリファレンスだけでなくチュートリアルもここを見るのが良いでしょう。 Google で検索すると上位にきますので、必然的に本家のチュートリアルを見ることになると思います。 ただし、SDK のバージョンによってアプリケーションディスクリプタの名前空間が異なりますので、バージョンが最新であるかを確認する必要があります。 特に、バージョン 2.5 からはバージョンの記法が変わりましたので注意が必要です。

セットアップの手順は次のようになりますので、順番に見ていきましょう。

  1. Adobe のサイト から AIR SDK の ZIP をダウンロードして展開する。
  2. プロジェクトに最低限必要なファイルを準備する。
  3. ディスクリプタファイル (application.xml) を編集する。
  4. デバッグ起動で動作を確認する。

SDK の配置

いずれのチュートリアルでも、SDK の bin ディレクトリにパスを通して... という書き方なので、最初から好き嫌いが別れるかもしれません。 複数のマシンで開発する場合は揃えた方が良いと思いますので、AIR の SDK は次の場所にインストール (ZIP を展開) します。 (もちろん、標準的な置き場所があるならそちらの方がベターですが、見つけられませんでした。)

Windows の場合:C:\Program Files\Adobe\AdobeAIRSDK-2.5
Linux の場合:/usr/local/adobe/AdobeAIRSDK-2.5
Mac OSX の場合:/Applications/Adobe/AdobeAIRSDK-2.5

Adobe のサイト から AIR SDK の ZIP をダウンロードして展開します。 OS によってダウンロードすべきファイルが異なります。 展開したアーカイブにはバージョン番号が付いていませんので、後から識別できるように手動で変更します。 必要があればシンボリックリンクなどを作成してデフォルトの SDK を指定できるようにすると良いかもしれません。

例

$ sudo ln -s /usr/local/adobe/AdobeAIRSDK-2.5 /usr/local/adobe/AdobeAIRSDK

プロジェクトに必要なファイルの準備

AIR のプロジェクトには、XML 形式のアプリケーションのディスクリプタファイルが必要です。 後でコマンドライン引数に与えることになりますので名前は何でも良いと思いますが、ここでは application.xml としておきます。 ディスクリプタファイルは適当なチュートリアルからコピーしても構わないと思いますが、 SDK に雛形が付属していますので、そこからコピーするのが良いと思います。 初めは分からないことも多く書かれていて非常に冗長ですが、後で機能を拡張するときに役に立つはずです。

JavaScript でアプリケーションを記述する場合は air オブジェクトを利用可能にしてくれるエイリアスファイル (AIRAliases.js) もあると便利です。 これも SDK に付属していますので、そこからコピーします。

最後に、アプリケーションの入り口となる HTML ファイルが必要です。 もちろん、このファイルの名前も任意に指定できます。 試しに プロジェクト名.html としておきます。

ここまでの手順を順番に実行すれば良いのですが、手動でやると間違えてしまうこともありますので セットアップ用スクリプト を用意します。 Python がインストールされている環境で次のように実行します。

$ wget --no-check-certificate -O air-quickstart.py https://github.com/skitazaki/sandbox/raw/master/src/d74.py

$ python air-quickstart.py -d "C:\Program Files\Adobe\AdobeAIRSDK-2.5" sample
C:\Program Files\Adobe\AdobeAIRSDK-2.5\bin\adl application.xml
C:\Program Files\Adobe\AdobeAIRSDK-2.5\bin\adt -certificate -cn SelfSigned 1024-RSA sampleCert.pfx samplePassword
C:\Program Files\Adobe\AdobeAIRSDK-2.5\bin\adt -package -certificate sampleCert.pfx -password samplePassword sample.air application.xml sample.html AIRAliases.js

$ ls sample
AIRAliases.js  application.xml  sample.html

オプション引数 -d に SDK をインストールしたディレクトリを指定して、コマンドライン引数でプロジェクト名を指定します。 3つのコマンドが出力されますが、このコマンドでアプリケーションの実行やパッケージングが可能です。 最後にプロジェクトディレクトリの中身を確認すると、上述のファイルが生成されていることが分かります。

ディスクリプタファイルの編集

ディスクリプタファイル (application.xml) を編集します。 先ほどのセットアップ用スクリプトでこれも実行できるようにしても良いかもしれません。

変更すべきは次の4つの要素です。

  • id ... DNS の逆形式 (com.example.app.air など衝突しなければ好みで)
  • filename ... パッケージングするファイル名 (sample にする)
  • initialWindow/content ... 起動時に表示するファイル名 (sample.html にする)
  • initialWindow/visible ... 起動時に表示するかどうかのフラグ (まずは true にしておくのが分かりやすい)

デバッグ起動で動作を確認

adl コマンドで起動を確認します。 PATH を通しておくことをお勧めする説明が多いですが、個人的にはとりあえずフルパスの方が分かりやすいと思います。 引数にはディスクリプタファイルを指定します。

$ cd sample
$ "C:\Program Files\Adobe\AdobeAIRSDK-2.5\bin\adl" application.xml

次のようなウィンドウが立ち上がれば成功です。

パッケージング

次に、パッケージを作成します。 自己署名ファイルを作成し、それを参照して .air ファイルを作成します。 コマンドオプションを覚えるのは大変なので、Windows の場合は make.bat 、Unix 系の場合は Makefile を書きます。 Sphinx と同じように、アーキテクチャを問わずに make とタイプするだけでよくなります。 また、ここで絶対パスを使うようにしておくと環境変数 PATH を汚染する必要がありません。

make.bat

@ECHO OFF

REM Command file for AIR application

::set BASEDIR=%PROGRAMFILES(x86)%\Adobe\AdobeAIRSDK-2.5
set BASEDIR=%PROGRAMFILES%\Adobe\AdobeAIRSDK-2.5
set ADT=%BASEDIR%\bin\adt.bat
set ADL=%BASEDIR%\bin\adl.exe

set AIR_DESCRIPTOR=application.xml
set AIR_PACKAGE=sample.air
set AIR_SCRIPTS=sample.html AIRAliases.js

set CERTIFICATE=sampleCert.pfx

if "%1" == "" goto help

if "%1" == "help" (
    :help
    echo.Please use `make ^<target^>` where ^<target^> is one of
    echo.  run     to start up application
    echo.  init    to make a samle certificate file
    echo.  package to make a ".air" package
    goto end
)

if "%1" == "run" (
    echo. "%ADL%"
    "%ADL%" "%AIR_DESCRIPTOR%"
    goto end
)

if "%1" == "init" (
    "%ADT%" -certificate -cn SelfSigned 1024-RSA %CERTIFICATE% samplePassword
    goto end
)

if "%1" == "package" (
    "%ADT%" -package -storetype pkcs12 -keystore %CERTIFICATE% -storepass samplePassword "%AIR_PACKAGE%" "%AIR_DESCRIPTOR%" %AIR_SCRIPTS%
    goto end
)

:end

Makefile

BASEDIR = /Applications/Adobe/AdobeAIRSDK-2.5
#BASEDIR = /usr/local/adobe/AdobeAIRSDK-2.5
ADT = $(BASEDIR)/bin/adt
ADL = $(BASEDIR)/bin/adl

AIR_DESCRIPTOR = application.xml
AIR_PACKAGE = sample.air
AIR_SCRIPTS = sample.html AIRAliases.js

CERTIFICATE = sampleCert.pfx

all:
    $(ADL) $(AIR_DESCRIPTOR)

init:
    $(ADT) -certificate -cn SelfSigned 1024-RSA $(CERTIFICATE) samplePassword

package:
    $(ADT) -package -storetype pkcs12 -keystore %CERTIFICATE% -storepass samplePassword $(AIR_PACKAGE) $(AIR_DESCRIPTOR) $(AIR_SCRIPTS)

.phony: all

あとはコマンドプロンプトなどから次のように実行します。 sample.air が生成されれば成功です。

$ make init

$ make package

パッケージにまとめるファイルを追加する場合には AIR_SCRIPTS に追記していきます。 たとえば jQuery を使う場合には次のようにします。(make.bat の場合)

set AIR_SCRIPTS=sample.html AIRAliases.js jquery-1.4.4.min.js

アンドロイド用のパッケージを生成する場合には -target オプションで apk を指定すれば良いようです。

あと、 make run で動作を確認できます。

終わりに

AIR の SDK を使って .air パッケージを作成してみました。 調べてみると、想像以上にドキュメント類が充実していて驚きました。 今回は簡単なスクリプトを自作しましたが、この手のことはアプリケーションのフレームワークや統合開発環境 (たとえば Aptana Studio ) に委ねてしまう方が良いでしょう。 とはいえ、実際に何が起こっているかを確認しておくことも大事だと思いますので、好き好きではあります。

「一度書けばどこでも動く」という考えは正しくもありそうでないこともあり、、、というのが現実だと思いますが、 手軽にアプリケーションを作れるようになってきたのは間違いないと思います。 あとは Xperia がバージョン 2.2 にアップデートしてくれると嬉しいですね。

2008年11月6日

ジェネレーターと再帰関数って同じ用途に使うことがあったっけかな、と思い、ちょっとメモしておきます。 無限に続くリストを作成するためにジェネレーターを利用することは全くもってその通りですが、同じ用途で再帰関数を使う局面はあまりないような気がします。遅延評価が関係すると事情は異なるかもしれませんが、yield する箇所で遅延させれば全てジェネレーターの範疇に収まりそうです。 再帰関数は、フィボナッチ数列のナイーブな実装に代表されるように、原始的な状態が決まるまで次の状態が決まらない場合に使うことが多いと思います。このため、前の状態が決まるまで評価を遅延させていると考えられます。しかし、無限に続くようなリストを作成することは難しくなります。前の状態を尋ねることが出来るのは、後続の状態だけだからです。100番目の状態を尋ねられるのが 101番目以降の状態だけだとすれば、無限番目の状態を尋ねられるのは何番目でしょうか? という数学の問題になってしまいます。別に、可算無限 / 非可算無限の違いをどうこうということではありません。単に、最後が分からないと評価を開始できない、というだけです。 一方で、ジェネレーターは次の状態が存在するまで原始的な状態を拡張していく方法です。簡単な数の数え上げで考えると、100 の次は 101 で、その次は 102 ... と単調に増加させていくことができます。再帰関数は上界が決まらないと評価が始められないことに対して、ジェネレーターは上界を意識せずに評価を進めることができます。 結局のところ、特性の異なる二つの考え方を渾然一体とするのは危険だと言えそうです。 なんとなくの思いつきですが、Python で再帰関数とジェネレーターの、おそらく一番簡単なサンプルを書いてみました。
# -*- encoding: utf-8 -*-

def rec(query):
    if len(query):
        rec(query[1:])
        print query

def gen(query):
    while len(query):
        yield query[0]
        query = query[1:]

sample = "hoge"
print "\n\tsample query: %s\n" % sample
print "---------------------------------------- "
print " recursive printing... "
rec(sample)
'''
e
ge
oge
hoge
'''

print "---------------------------------------- "
print " generative printing... "
s = ""
for i in gen(sample):
    s += i
    print s
'''
h
ho
hog
hoge
'''
ちなみに、手元の「みんなの Python」(250ページ) には、次のような記述があります。
yield 文と return 文を、一つの関数で使うことはできません。
上記サンプルを書いているときにエラーが出たので読んでみましたが、そりゃそうだ、という話でしたとさ。

2008年6月14日

iPodでRFCを読むためのシェルスクリプト

標準ドキュメントを読み進めないといけないので、iPodの「ノート」で持ち運べるようにしてみました。これで通勤電車の中でも読み進めることができます。文字が小さいのが欠点ですが、そこは若さでカバーするという方向性で。 iPhoneを購入すればネットワーク越しにドキュメントを読めるようになりますが、生憎と私はauユーザーです。そもそも、地下鉄通勤だと電波が使えないので、ローカルに保存した方が何かと都合が良いのです。パケット代もかかりませんしネットワークによる遅延もありません。 というわけで、iMacにiPodをつないでシェルスクリプトを実行するとRFCドキュメントをiPodに転送できるようにしました。 iPodのノート機能では一つのテキストファイルは4KBまでしか表示されないので、適当なファイルサイズに分割する必要があります。バイト長をいちいち計算しても構わないのですが、RFCの文書では改頁記号(バックスラッシュ+F)を使ってくれているので、これで頁毎にファイルに保存することにします。 MicrosoftのWordが普及した現在だとテキストファイルは見栄えがしませんが、こうして様々な機器に簡単に転送できますので、定型のフォーマットを決めておくことは大事だと思いました。 ######################################## 使い方 「rfc2ipod.sh」の「IPODNAME」を変更すればMacだと利用できると思います。Windowsの場合はそもそもシェルスクリプトが使えないのでcygwinとかが必要ですが、「IPOD」の部分を変更すれば多分大丈夫だと思います。
  1. 「split-by-page.awk」と「rfc2ipod.sh」を適当なディレクトリに保存します。
  2. 「rfc2ipod.sh」に実行権限を付加します。
  3. iPodを接続します。
  4. コマンドを実行します。
デスクトップにショートカットアイコンを作成すると簡単に実行できそうですが、引数を与える方法が分かりません...AppleScriptとかだと簡単にできるのかもしれませんが、これはいつか気が向いたときにでも。 HTTP-1.1に関するRFCを取得する方法は次のようになります。
$ chmod +x rfc2ipod.sh
$ ./rfc2ipod.sh 2616
読み終わったら掃除します。
$ ./rfc2ipod.sh clean
######################################## split-by-page.awk
{
    split(FILENAME, filename, ".")
    if($0=="\f" || !output)
        output = sprintf("%s-%03d.txt", filename[1], ++page);
    else
        print $0 >> output;
    close(output)
}
rfc2ipod.sh
#!/bin/sh

##
# @file   rfc2ipod.sh
# @author Kitazaki, Shigeru
# @see    http://developer.apple.com/ipod/iPodNotesFeatureGuideCB.pdf
# @brief  Retrieve RFC document via HTTP,
#         and split document into page by page.
#         This is useful to save in iPod, which is
#         restricted 4KB for one text file.

END_POINT=http://www.ietf.org/rfc

SPLITTER=split-by-page.awk

IPODNAME=KSHIGERU
IPOD=/Volumes/$IPODNAME

if [ -n "$1" ];
then
    case $1 in
        [0-9]*)
            if [ -d $IPOD ];
            then
                doc=rfc$1.txt
                wget -O $doc $END_POINT/$doc
                awk -f $SPLITTER $doc
                mv  rfc$1-* $IPOD/Notes
            else
                echo No iPod device in \'$IPOD\'.
            fi
            ;;
        clean)
            rm -f rfc*.txt
            if [ -d $IPOD ];
            then
                rm -f $IPOD/Notes/rfc*.txt
            fi
            ;;
        *)
            echo Enter valid number.
            ;;
    esac
else
    echo Usage:
    echo '\t' $0 RFC-number
    echo '\t' $0 clean
fi

2008年4月28日

パスの通っているコマンドを全て表示する

awkが必要ですが、簡単に書けました。しかし、シェルスクリプトではいつもクォーテションに悩まされます。まだまだ書いている量が足りないことを痛感してしまいます。

下記スクリプトの問題点として、Windows環境(cygwin)だとパスに空白が含まれる(Program Files)ためこのままでは使えません。適当に環境に併せて中間処理を挟む必要があります。

#!/bin/sh
# command-list.sh

temporary="temporary.data"

for p in `echo $PATH | awk -F : '{for(i=1; i<=NF; i++) print $i}'`
do
    ls $p >> $temporary
done

sort $temporary | awk '{printf "%04d    %s\n", NR, $1;}'

rm -f $temporary

手許の環境 (Mac OSX) で実行してみると次のようになりました。

$ ./command-list.sh | wc -l
    2205
つまり、利用可能なコマンドは2205個存在しています。自分が使っているものなんて氷山の一角にも満たないことがわかります。


man以外のawkに関するドキュメント→ NR, NFに関しては非常に便利なので覚えておきたい。