ワンライナーを使うと
ワンライナーを使うと、置換や出力処理がとっても便利になります。
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
-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
-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円(税込)
cut コマンドと同じことをruby で
cut コマンドで
takuya@air:~/Desktop$ cut -d',' -f 1 test.csv コーヒ・フラペチーノ ダークモカチップフラペチーノ 抹茶クリームフラペチーノ バニラクリームフラペチーノ
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
takuya@air:~/Desktop$ ruby -pe "" test.csv test.csv コーヒ・フラペチーノ,420 ダークモカチップフラペチーノ,490 抹茶クリームフラペチーノ,470 バニラクリームフラペチーノ,470 コーヒ・フラペチーノ,420 ダークモカチップフラペチーノ,490 抹茶クリームフラペチーノ,470 バニラクリームフラペチーノ,470
uniq コマンドと同じことをruby ワンライナーで
takuya@air:~/Desktop$ ruby -e " puts ARGF.map{|e| e.split(/,/).first}.sort.uniq" test.csv 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