Rubyワンライナー入門
先日仕事中、一瞬の隙も見逃さずに情報収集できるRubyワンライナーとスクリプトというネタエントリを書いたのだが、その際Rubyのワンライナーをもう少しまともに理解したいと思ったので入門してみた。手元のRubyは1.9.2
はじめに
Rubyのワンライナーは、rubyコマンドに色々なオプション(-eや-nなど)をつけて実行する。各オプションの網羅的な解説が見たければ、コマンドラインでは$ man rubyで閲覧できるし、webではるりまサーチで参照できる。ただ、これらは網羅的すぎるので、以下よく使うオプションとその周辺情報についてまとめた。
-n
プログラム全体がwhile gets ... endというループで囲まれているように動作する。ちょっとややこしい。
例: hoge.txtとfuge.txtの内容を表示
$ ruby -ne 'puts $_' hoge.txt fuge.txt
理解するには
Kernel.#gets、ARGF、$_について理解する必要がある
Kernel.#gets
ARGFから一行読み込んで、それを返します。...読み込んだ文字列は組み込み変数 $_ にもセットされます。...
http://rurema.clear-code.com/1.9.2/method/Kernel/m/gets.html
つまり、以下は同義
$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt
ざっくりいうと、以下のような流れになる
hoge.txtとfuge.txtを連結した仮想ファイル(ARGF)をセット
↓
ARGFから1行読み込み、$_にセット。読み込めた場合は$_を出力してループ
ちなみに
上記では出力の部分をputs $_としているが、これはKernel.#printで代替できる。
Kernel.#print
引数を順に標準出力 $stdout に出力します。引数が与えられない時には変数 $_ の値を出力します。...
http://rurema.clear-code.com/1.9.2/method/Kernel/m/print.html
つまり、以下は全て同義
$ ruby -ne 'print' hoge.txt fuge.txt
$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt
-p
nオプションとほぼ同じ。nオプションと同じくプログラム全体をwhile gets...endループするが、さらに各ループの最後にprintする。つまり、printが省略できるということ。なので、以下は全て同義。
$ ruby -pe '' hoge.txt fuge.txt
$ ruby -ne 'print' hoge.txt fuge.txt
$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt
$_を破壊的メソッドで変換して出力するような場合に便利
例: hoge.txtとfuge.txtの内容を全て大文字にして表示
$ ruby -pe '$_.upcase!' hoge.txt fuge.txt
-a
オートスプリット。nかpと一緒に使う。各ループの先頭で$F = $_.splitをを実行する。
例: カレントディレクトリの情報を配列に変換して表示
$ ls -laF | ruby -ane 'p $F'
-F
$;(入力フィールドセパレータ。splitのデフォルト区切り文字)を設定
例: 環境変数PATHを:で分割して改行表示
$ echo $PATH | ruby -F: -ane 'puts $F'
-r
ライブラリ読み込み。
例: yahooのhtmlを取得
$ ruby -r open-uri -e 'open("http://www.yahoo.co.jp") {|f| puts f.read}'
ちなみに、複数のライブラリを読み込みたい場合は-r を複数書く。
例: facebookのapiからマークザッカーバーグのJSONを取得しハッシュに変換
$ ruby -r open-uri -r json -e 'open("http://graph.facebook.com/zuck") {|f| p JSON.parse(f.read)}'
BEGIN, END
オプションでは無いのだが、普段あまり使わないRubyの構文BEGINとEND(begin...endとは全くの別物)がワンライナーだと結構使われるようだ。
例: 全行が整数のnumber.txtの合計値を表示
$ ruby -ne 'BEGIN{$sum = 0}; $sum += $_.to_i; END{puts $sum}' number.txt
BEGINとENDをつけないと、毎行読み込むごとに$sum = 0; と puts $sumが実行されてしまうので意図した結果にならない
BEGIN
初期化ルーチンを登録します。BEGINブロックで指定した文は当該ファイルのどの文が実行されるより前に実行されます。...
http://doc.ruby-lang.org/ja/1.9.2/doc/spec=2fcontrol.html#BEGIN
END
「後始末」ルーチンを登録します。END ブロックで指定した文はインタプリタが終了する時に実行されます。Ruby の終了時処理について詳しくは 終了処理を参照してください。...
http://doc.ruby-lang.org/ja/1.9.2/doc/spec=2fcontrol.html#END