Rubyワンライナー
まえがき
他にも武器が欲しい
perlもワンライナーに強いけれど、今更やるのもなぁという気持ち モジュールをrequireできるのが強い
Rubyの構文よく知らないけれど雰囲気でいけるいける オプション
癖でとりあえずruby -lane 'puts うんちゃら'で実行してしまうけれど、それぞれの意味はここに記載
ワンライナースクリプト -e
code:sh
ruby -e 'puts "hello"'
標準入力とか特に扱わないならこれだけで良い
標準入力を受ける -n
入力1行を格納する変数 $_ (awkでいう $0)
現在処理している行数を格納する変数 $. (awkでいう NR)
code:sh
echo sushi | ruby -ne 'puts $_'
cat << E | ruby -ne 'print "#{$.} : #{$_}"' hello
world
HELLO
WORLD
E
BEGIN, END
code:sh
seq 10 | ruby -ne 'BEGIN{ puts "id" }; puts $_; END{ puts "end" }'
注意点はブロックの終了後に;が必須なこと
これはセミコロンが抜けてるので構文エラーになる
code:sh
seq 10 | ruby -ne 'BEGIN{ puts "id" } puts $_; END{ puts "end" }'
$F変数に配列要素として代入される
code:sh
echo 1 2 3 | ruby -ane 'puts $F2' フィールドの区切り文字の指定 -F
-F',' みたいにFに区切り文字をくっつけないとダメ
code:sh
echo 1,2,3 | ruby -F',' -lane 'puts $F'
# こっちはエラー
echo 1,2,3 | ruby -F ',' -lane 'puts $F'
行末処理をする -l
このオプションを指定しないと$_の末尾には改行文字が含まれる
指定すると$_の改行文字を捨ててくれる
code:sh
seq 10 | ruby -ane 'BEGIN{ sum = 0 }; sum += $_.chomp.to_i; END{ print sum }'
seq 10 | ruby -lane 'BEGIN{ sum = 0 }; sum += $_.to_i; END{ print sum }'
$_をprint -p
-nとほぼ同じだけれど、$_をprintする
putsを省略できる
$_を上書きする必要があるため副作用のあるメソッドを呼ぶ必要がある
rubyではメソッドが自身のインスタンスに対して破壊的変更を加えるものは!がメソッド名に含まれる 例: tr!
code:sh
echo sushi | ruby -pe '$_.tr!("a-z", "A-Z")'
モジュールを読み込む (require) r
code:sh
ruby -rdate -e 'puts Date.today'
とりあえず
ruby -lane 'スクリプト'ってやっとけばawkと同じ感覚で実行できる 芸
1行目を無視する
awk '1<NR'相当
後置ifを使う
code:sh
seq 3 | ruby -lane 'puts $_ if 1 < $.'
文字列の n 文字目の文字を取得
インデックス0アクセスは先頭の文字に
インデックス-1アクセスは末尾の文字に
0..終端でレンジで文字列を取得
code:sh
ruby -e 'puts "hello"0' # -> h ruby -e 'puts "hello"-1' # -> o ruby -e 'puts "hello"0..-2' # -> hell 集計
合計
code:sh
seq 10 | ruby -ne 'BEGIN{ sum = 0 }; sum += $_.to_i; END{ puts sum }'
平均
code:sh
seq 10 | ruby -ne 'BEGIN{ sum = 0 }; sum += $_.to_i; END{ puts sum.to_f / $. }'
変数初期化のためだけのBEGINを省略
var ||= 0は変数が未定義の場合だけ0を代入する
code:sh
seq 10 | ruby -ne 'sum ||= 0; sum += $_.to_i; END{ puts sum.to_f / $. }'
GroupByしてsum
||=を使えばキー未定義のハッシュマップの初期化もできる
code:sh
cat << EOS | ruby -F' ' -lane 'm ||= {}; k = $F0; mk ||= 0; mk += $F1.to_i; END{ m.each{ |k,v| puts "#{k} #{v}" } }' apple 100
banana 200
apple 100
orange 300
banana 200
banana 200
EOS
正規表現マッチした部分だけ加工 gsub
gsub!だと破壊的変更をする
code:sh
ruby -e 'puts "hello".gsub(/l/, "L")'
echo 1年と12ヶ月と22日 | ruby -pe '$_.gsub!(/\d{2,}/){|s| s.tr("0-9", "0-9")}'
変数を文字列に埋め込む "#{var}"
code:sh
ruby -e 'x = "hello"; puts "<#{x}>"'
変数を埋め込むというより、#{}の中に式がそのまま埋め込める
code:bash
ruby -e 'puts "#{1 + 1}"' # -> 2
リストを要素ごとに処理 map
code:sh
こういう引数にメソッドを受け取るメソッドでそのまま引数を渡せる場合は&:メソッド名という書き方もできる
code:sh
echo h e l l o | ruby -lane 'p $F.map(&:upcase)'
# 以下と結果は同じ
echo h e l l o | ruby -lane 'p $F.map{|i| i.upcase}'
リストを要素ごとに処理しつつ、インデックスを付与 with_index
code:sh
ランダムに要素を入れ替える shuffle
code:sh
grep検索 grep
code:sh
グループマッチした箇所を取り出すことも可能
code:sh
# -> $1 = 山田, i = 山田たろう
並べ替え sort
code:sh
ruby -e 'puts ("ど","う","ぶ","つ","の","森" * 199999).sort_by{rand}.each_slice(6).to_a.map.with_index{|n, i| i.to_s + " " + n.join("")}' | grep どうぶつの森 #シェル芸 現在日時 Time.now
code:sh
ruby -e 'puts Time.now'
ruby -rdate -e 'puts Date.today'
日時演算 next_day prev_day
他にもいろいろある
code:sh
ruby -rdate -e 'puts Date.today.next_day(3)' # 3日後
ruby -rdate -e 'puts Date.today.prev_day(7)' # 7日前
日付をパース
code:sh
ruby -rtime -e 'puts Time.parse("2021/01/15")'
UTCをJSTに変換
code:sh
ruby -rtime -e 'puts Time.parse("2021/01/15 00:00:00 +00:00").getlocal("+09:00")'
繰り返し times each
code:sh
ruby -e '10.times{ puts 1 }'
ruby -e '(1 .. 10).each{ |i| puts i}' # 10 を含む
ruby -e '(1 ... 10).each{ |i| puts i}' # 10 を含まない
番号指定パラメータ
_1~_9まで
code:sh
ruby -e '(1..10).each{ |i| puts i }'
# ↑↓同じ
ruby -e '(1..10).each{ puts _1 }'
特定の文字を含む行だけ出力
~ /REGEXP/ これは /REGEXP/ ~ $_と等価
code:sh
seq 9 | ruby -lane 'puts $_ if ~ /2468/' 多重代入
配列をそれぞれ別々の変数に代入できる
code:sh
ruby -e 'a,b = 1,2,3; puts a, b' # -> 1, 2 code:sh
cat << EOS | ruby -F, -lane 'a,b,c = $F; puts b' # -> 1, 2, 3 だけ出力される
a,1,A
b,2,B
c,3,C
EOS
code:sh
ruby -rjson -e 'puts JSON.generate({"name":"taro", "age":22, "admin":true})'
標準入力からJSONを読み込んでハッシュに変換
code:sh
cat << JSON | ruby -rjson -e 'puts JSON.parse(STDIN.read)'
{
"id":1,
"name":"taro",
"admin":true
}
JSON
code:sh
cat << CSV | ruby -rcsv -e 'CSV(STDIN).each{|row| p row }'
"id","name","age"
"1","yamada","22"
"2","suzuki","24"
"3","uehara","19"
CSV
CSVをJSONに変換
code:sh
cat << CSV | ruby -rcsv -rjson -e 'puts JSON.generate(CSV(STDIN).map{|x| x})'
"id","name","age"
"1","yamada","22"
"2","suzuki","24"
"3","uehara","19"
CSV
10進数(integer)を2進数(string)に
code:ruby
puts 255.to_s(2)
2進数(string)を10進数(integer)に
code:ruby
puts 1100.to_i(2)
日本語の文字のコードポイントを取得
code:ruby
puts "あ".ord
puts "あいうえお".chars.map(&:ord)
コードポイントを文字に戻す
code:ruby
puts 97.chr # -> a
puts 12354.chr(Encoding::UTF_8) # -> あ
参考