rb - 標準出力をRubyで処理
開発者であればターミナル操作を行う機会は多いでしょう。各コマンドは独立しており、パイプなどを通じて一繋ぎの操作を実現します。しかしシェル芸という言葉があるくらい、熟練者とそうでない人とで実現できるものが異なります。さらにシェルスクリプトですべてを記述するのはコード量も多くなったり、正規表現を駆使しなければならないでしょう。 そこで使ってみたいのがrbです。標準出力を受け取って、Rubyで処理が書けるユーティリティです。
rbの使い方
例えば df の結果をサイズ順に並び替えます。
$ df -h | rb '[first].concat drop(1).sort_by { |l| l.split[-2].to_f }'
Filesystem Size Used Avail Capacity iused ifree %iused Mounted on
/dev/disk1s4 466Gi 5.0Gi 66Gi 8% 5 9223372036854775802 0% /private/var/vm
/dev/disk2s1 119Gi 73Gi 46Gi 62% 2101576 4292865703 0% /Volumes/SD
devfs 211Ki 211Ki 0Bi 100% 729 0 100% /dev
map -hosts 0Bi 0Bi 0Bi 100% 0 0 100% /net
map auto_home 0Bi 0Bi 0Bi 100% 0 0 100% /home
ファイルを検索して、拡張子ごとにファイル数をリストアップします。
$ find . -type f | rb 'group_by(&File.method(:extname)).map { |ext, o| "#{ext.chomp}: #{o.size}" }'
: 27
.sample: 10
.idx: 1
.pack: 1
.js: 1
.py: 1
.json: 1
rbは標準出力をRubyの変数として受け取ります。後はevalで評価しています。コードは以下の通りです。
#!/usr/bin/env ruby
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はRuby製のオープンソース・ソフトウェア(MIT License)です。
thisredone/rb: Turns Ruby into a versatile command line utility