yhara.jp

Recent Posts

sedやawkが覚えられないRubyistのための「rbコマンド」

2018-12-21
Tech

この記事はRuby Advent Calendar 2018の21日目の記事です。

今年のある日、rubyweeklyで流れてきたのがこれ。どうやらsedやawkみたいなワンラインプログラムが、Rubyで簡単にできるようになるみたいだが…?

-nは覚えられない

一応、Ruby本体にも-nや-pという、ワンライナ向けのオプションがあるんだよな。そう、あることは知っている。でも使い方は覚えてない。

sedやawkも一緒で、使えたら便利なんだろうなーと思いつつ、未だに覚えてない(少なくとも何も見ずに書ける程には)。

そこでrbコマンド?

rbコマンドのいいところは、「普段Rubyを使ってるときの感じのままで」ワンライナが書けるところだ。

とりあえず例を見てもらおう。rbコマンドには1行ずつ処理する「lineモード」と、ファイル全体がEnumeratorとして取れる「linesモード」の2種類がある(命名は筆者)が、よく使うのは前者だろう。とりあえず-lオプションでlineモードを使ってみる。

psからpidを抜き出す

例として、psコマンドの出力からPID部分だけを抜き出すことを考える。PIDは各行の先頭にあるので、Rubyist的に考えると、「行をsplitして0番目を取ればよさそう」となる。

ruby -pだと行は$_で取得するのだが、rbコマンドでは「行はどうやって取るんだっけ」と考える必要はない。行に対して何をするかだけ書けばいいからだ。

$ ps | rb -l 'split[0]'
31728
31789
33161
34859
35196
54235
53874

このように、「splitして0番目を取る」という「やりたいこと」だけ書けば動いてくれるのがrbコマンドなのだ。

インストール方法

さっそく使ってみたくなった人のために、インストール方法を解説しておく。といってもインストールはすごく単純だ。rbコマンドはたったの9行しかないからだ。以下の内容をrbというファイル名で作成し、PATHの通ったところに置くだけ。

#!/usr/bin/env ruby
File.join(Dir.home, '.rbrc').tap { |f| load f if File.exists?(f) }

def execute(_, code)
  puts _.instance_eval(&code)
rescue Errno::EPIPE
  exit
end

single_line = ARGV.delete('-l')
code = eval("Proc.new { #{ARGV.join(' ')} }")
single_line ? STDIN.each { |l| execute(l.chomp, code) } : execute(STDIN.each_line, code)

実装を読む

というわけで上のプログラムがrbコマンドの全貌なのだが、どういう実装になっているのだろうか?先ほどの実行例をもう一度見てみる。

$ ps | rb -l 'split[0]'

_.instance_eval(&code) という部分が肝で、各行を表すStringを_として、与えられたプログラムcodeがinstance_evalで実行される。

これにより、code内ではStringクラスのメソッドが好きに呼べるし、またselfで文字列全体を取ることもできる。以下のようにローカル変数を宣言してもちゃんと動く。

$ ps | rb -l 'a = split; "#{a.first} #{a.last}"'

linesモード

最後に「linesモード」について補足しておこう。-lを付けなかった場合は、入力全体を行ごとのEnumeratorにしたものがselfになる。

例として、csvファイルのうち「2018-09」が入った行だけを出力することを考えよう。普通のRubyプログラムならlines.select{...}などと書くところだが、rbコマンドの場合はlines.より後だけを書く。

$ cat log.csv | rb 'select{|l| l =~ /2018-09/}'
2018-09-01,...
2018-09-02,...

個人的にはlineモードの方が使いたい機会が多そうなので、そっちがデフォルトでも良かったような気がする。がしかし、rbコマンドはたった9行のスクリプトなので、そう思うならそのように変えてしまえば良い。いろいろカスタマイズして、君だけの最強のrbコマンドを作り上げよう!

More posts

Posts

(more...)

Articles

(more...)

Category

Ads

About

About the author