それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ruby ワンライナーの使い方まとめ

Rubyワンライナーについて、書いていきます。

ワンライナーを使うと

ワンライナーを使うと、置換や出力処理がとっても便利になります。

ruby -ne '$_.gsub!(/takuya/,"takuya_1st")' -i my_blog.txt

今回使うサンプルファイル

はじめに次のようなファイルを用意しました。こんかいはこのサンプルを使います

コーヒ・フラペチーノ   420
ダークモカチップフラペチーノ 490
抹茶クリームフラペチーノ 470
バニラクリームフラペチーノ 470

基本の -e オプション

基本の-eオプションです。ruby スクリプトを直接指定する方法です。

takuya@air:~/Desktop$ ruby -e 'puts ARGF.read'  test.txt
コーヒ・フラペチーノ   420
ダークモカチップフラペチーノ 490
抹茶クリームフラペチーノ 470
バニラクリームフラペチーノ 470

ループ省略する -n オプション

-ne をつけると、 while gets ... end に入っているように動作します。ループ構文を省略出来ます、

takuya@air:~/Desktop$ ruby -ne 'puts $_'  test.txt
コーヒ・フラペチーノ   420
ダークモカチップフラペチーノ 490
抹茶クリームフラペチーノ 470
バニラクリームフラペチーノ 470
特殊変数 $_

変数$_が出てきました。
ne オプションを使うと変数$_には直前に読み込んだ行が入ります。

これは次のruby 文で説明できます。

while gets 
 puts  $_
end

と書いたたら動きます。gets/$_はPerlの構文からもらってきたものです。

gets は ARGF.readline と同じことです。

-p オプションでputs も省略する

ここまで読めばワンライナーを使えるようになります。ここからは、もっと便利で使えるオプションを紹介します。

puts を毎回書くのを省略できます。

takuya@air:~/Desktop$ ruby -pne ''  test.txt
コーヒ・フラペチーノ   420
ダークモカチップフラペチーノ 490
抹茶クリームフラペチーノ 470
バニラクリームフラペチーノ 470

前半まとめ。cat 相当のruby ワンライナー6種

ここまでファイルの読込・ループ・出力処理に関するオプションを紹介しました。この違いを見てみましょう。

-e と ARGF / gets / $_ 特殊変数の関係がよく分かるように、同じことを違う書式で書きました。

-e を使った cat コマンド処理
ruby -e   'ARGF.each dp |e| puts e end '  test.txt
ruby -e   'while ARGF.gets ; puts $_ ;end' test.txt
ruby -e   'while gets ; print ;end'              test.txt
-n -p -e オプションでの比較

このcat コマンド・ワンライナーがオプションが変わったらどうなるかを比較して見てみましょう。

ruby -e   'while gets ; print ;end'         test.txt
ruby -ne  'puts $_'           test.txt
ruby -pne ''           test.txt


オプションが増える度にコードを省略されるのが見て取れるでしょうか。

オプションを覚えればワンライナーがスッキリします。

-pne の使い方

頻繁に使う -npeの使い方について

takuya@air:~/Desktop$ ruby -pne '$_ =  $_.split(/ /).last'  test.txt
420
490
470
470

-nep オプションでを、 $_ 変数に代入処理を入れるのが多いです。

破壊的メソッドで使うと便利です。
ruby -pne '$_.gsub!(/aa/, "bb")'  test.txt

$_ 変数を破壊的メソッドで直接書き換えも便利です。

更に進んだオプション -a -F -l -i

ここから先は、組み合わせで便利なる4つのオプションです。

-a オプション:split するなら、更に便利

ループの先頭で $F = $_.splitを実行して、分割してくれます。

$F特殊変数を使います。
以下の2つは同じに動作します。

ruby -anpe test.txt
ruby -e   'while gets ; $_.split! ; print ;end'         test.txt
実行サンプル
takuya@air:~/Desktop$ ruby -apne '$_=$F'  test.txt
["コーヒ・フラペチーノ", "420"]
["ダークモカチップフラペチーノ", "490"]
["抹茶クリームフラペチーノ", "470"]
["バニラクリームフラペチーノ", "470"]

区切り文字を指定したい -F オプションが便利

CSV ファイルの場合は区切り文字を明示的に指定すると楽になります。

  • F "," で区切り文字を指定して$Fを作ることが出来ます。

これは次と同じです。  ーF で指定した引数がsplit/,/に入ります。

ですので、以下の2つは同じに動作します。

ruby -F',' -anpe test.txt
ruby -e   'while gets ; $_.split!(/,/) ; print ;end'         test.txt

実行サンプル

takuya@air:~/Desktop$ ruby -F"," -ane 'p $_=$F'  test.csv
["コーヒ・フラペチーノ", "420\n"]
["ダークモカチップフラペチーノ", "490\n"]
["抹茶クリームフラペチーノ", "470\n"]
["バニラクリームフラペチーノ", "470\n"]

改行コードが邪魔なんで消す -l オプション

先ほどから、実行サンプル結果に 改行が含まれてきます。不要なときは消しましょう。

-l オプションで改行を消す

takuya@air:~/Desktop$ ruby -F"," -lane 'p $_=$F'  test.csv
["コーヒ・フラペチーノ", "420"]
["ダークモカチップフラペチーノ", "490"]
["抹茶クリームフラペチーノ", "470"]
["バニラクリームフラペチーノ", "470"]

ファイルの内容を書き換える

Rubyでファイルの内容を書き換えたいときは -i オプションを使う。

takuya@air:~/Desktop$ cp test.csv test2.csv
takuya@air:~/Desktop$ ruby -pne '$_.gsub!(/0/,"00, 10 個")' -i test2.csv
takuya@air:~/Desktop$ cat test2.csv
コーヒ・フラペチーノ,4200, 10 個
ダークモカチップフラペチーノ,4900, 10 個
抹茶クリームフラペチーノ,4700, 10 個
バニラクリームフラペチーノ,4700, 10 個


さらに、複数のファイルを纏めて書き換えることが出来る。

ruby -pne '$_.gsub!(/0/,"00, 10 個")' -i test2.csv test.3.csv test4.csv

集計したいときはBEGIN..ENDが便利

ARGF.each でEnumerableを作り でブロック使ってもいいんだけど、それだとワンライナーじゃない


こんなかんじで、BEGIN/ENDを指定したらループ前後処理を書くことが出来る

'BEGIN{ $total=0 };
  $total +=$F.last.strip.to_i;
END{ puts "合計\t"+($total*1.05).floor.to_s+"円" } '

BEGIN..ENDはAWK由来の構文でrubyでもワンライナーで大活躍中です。

実行サンプル
takuya@air:~/Desktop$ ruby -F"," -ane 'BEGIN{ $total=0 }; puts $F.join("\t"); $total +=$F.last.strip.to_i;END{ puts "-"*40;puts "合計\t"+($total*1.05).floor.to_s+"円(税込)" } '  test.csv
コーヒ・フラペチーノ     420
ダークモカチップフラペチーノ     490
抹茶クリームフラペチーノ     470
バニラクリームフラペチーノ     470
----------------------------------------
合計     1942円(税込)

rubyワンライナーlinuxコマンドっぽいことをやってみる

ここまで、覚えたら、ワンライナーさえあればLinuxコマンド無くても大丈夫なので車輪の再発明をして、ワンライナーを復習しましょう

cut コマンドと同じことをruby

cut コマンドで

takuya@air:~/Desktop$ cut -d',' -f 1 test.csv
コーヒ・フラペチーノ
ダークモカチップフラペチーノ
抹茶クリームフラペチーノ
バニラクリームフラペチーノ

ruby ワンライナー

takuya@air:~/Desktop$ ruby -F"," -lane  'puts $F[0]' test.csv
コーヒ・フラペチーノ
ダークモカチップフラペチーノ
抹茶クリームフラペチーノ
バニラクリームフラペチーノ

cat コマンドと同じことをRuby

cat コマンドならこう書きます。

takuya@air:~/Desktop$ cat  test.csv test.csv
コーヒ・フラペチーノ,420
ダークモカチップフラペチーノ,490
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470
コーヒ・フラペチーノ,420
ダークモカチップフラペチーノ,490
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470

rubyワンライナーならこう

takuya@air:~/Desktop$ ruby -pe "" test.csv test.csv
コーヒ・フラペチーノ,420
ダークモカチップフラペチーノ,490
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470
コーヒ・フラペチーノ,420
ダークモカチップフラペチーノ,490
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470

uniq コマンドと同じことをruby ワンライナー

rubyワンライナーでuniqコマンド

takuya@air:~/Desktop$ ruby -e " puts ARGF.map{|e| e.split(/,/).first}.sort.uniq" test.csv  test.csv
コーヒ・フラペチーノ
ダークモカチップフラペチーノ
バニラクリームフラペチーノ
抹茶クリームフラペチーノ

sed の代替 文字列の置換をワンライナー

sedも便利なんだけどね。rubyで出来たほうが嬉しい。

sedrubyワンライナー
takuya@air:~/Desktop$ ruby -pne '$_.gsub!(/0/,"00, 10 個")' test.csv
コーヒ・フラペチーノ,4200, 10 個
ダークモカチップフラペチーノ,4900, 10 個
抹茶クリームフラペチーノ,4700, 10 個
バニラクリームフラペチーノ,4700, 10 個

ファイルを書き換えるときは -i オプションです。

takuya@air:~/Desktop$ ruby -pne '$_.gsub!(/0/,"00, 10 個")' -i test.csv

grep の代替

grepの替りにも使えそうですね。

takuya@air:~/Desktop$ ruby -pne '$_=nil unless $_=~ /抹茶|バニラ/' test.csv
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470

ARGFなら、もっと単純に出来ますね

takuya@air:~/Desktop$ ruby -e 'puts  ARGF.grep /抹茶|バニラ/'  test.csv
抹茶クリームフラペチーノ,470
バニラクリームフラペチーノ,470

まとめ

一番便利なの出力フォーマットと置換じゃないでしょうか。

rubyワンライナーで置換とか、出力フォーマットを書き換えるのが便利だと思います。


ワンライナーでファイルの書き換えが出来るようになると相当捗ります。
設定変更をスクリプト化すれば役に立つんじゃないでしょうか

rubyワンライナーawk と同じように作られていますので、 awk の勉強にも一役買ってくれます。




http://d.hatena.ne.jp/mickey24/20110310/ruby_one_liner
http://d.hatena.ne.jp/maeharin/20130113/ruby_oneliner