Rubyワンライナーをいろいろ使ってみます。
目次
集計
1列の集計
1列の集計です。
1 |
ruby -e 'puts readlines.map(&:to_i).inject(&:+)' |
コマンド例
1 |
seq 10 | ruby -e 'puts readlines.map(&:to_i).inject(&:+)' |
seq 10
1 2 3 4 5 6 7 8 9 10 |
1 2 3 4 5 6 7 8 9 10 |
実行結果
1 |
55 |
1列の集計(-nオプション使用)
値の初期化にBEGIN句を書くのが面倒なので、||=演算子を使用しています。
1 |
ruby -ne 'sum||=0;sum+=$_.to_i;END{puts sum}' |
コマンド例
1 |
seq 10 | ruby -ne 'sum||=0;sum+=$_.to_i;END{puts sum}' |
実行結果
1 |
55 |
2列以上の集計
それぞれの列に数字が絶対に必要です。
1 |
ruby -e 'p readlines.map{|x| x.split.map(&:to_i)}.transpose.map{|x| x.inject(&:+)}' |
コマンド例
1 |
seq 10 | paste - - |ruby -e 'p readlines.map{|x| x.split.map(&:to_i)}.transpose.map{|x| x.inject(&:+)}' |
seq 10 | paste - -
1 2 3 4 5 |
1 2 3 4 5 6 7 8 9 10 |
実行結果
1 |
[25, 30] |
2列以上の集計(-nオプションと-aオプション使用)
特定の列に数字がない場合でも対応可能。数字がない場合は0が入ります。
1 |
ruby -nae 'sum||=[];$F.each_index{|i| sum[i]||=0;sum[i]+=$F[i].to_i};END{p sum}' |
コマンド例
1 |
seq 10 |paste - - | ruby -nae 'sum||=[];$F.each_index{|i| sum[i]||=0;sum[i]+=$F[i].to_i};END{p sum}' |
実行結果
1 |
[25, 30] |
ネットワーク
HTMLの取得
ウェブサーバーにGETリクエストを送ります。
1 |
ruby -ruri -rnet/http -e 'Net::HTTP.get_print(URI.parse(gets.chomp))' |
コマンド例
1 |
echo 'https://linuxcommand.net' | ruby -ruri -rnet/http -e 'Net::HTTP.get_print(URI.parse(gets.chomp))' |
HTMLの解析
上のHTMLの取得したデータをnetfileという名前のファイルに保存して、Nokogiriで解析します。
コマンド例は、このサイトのトップページに表示されている記事のタイトルを表示します。
コマンド例
1 |
cat netfile | ruby -rnokogiri -e 'puts Nokogiri::HTML.parse(readlines.join("\n")).css(".entry-title").map(&:text)' |
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 |
od - ファイルをバイナリで表示する comm - ソート済みファイルの行を比較する test - ファイルチェック・値の比較をする yes - 中断するまで文字列を出力し続ける echo - 文字列を表示する dirname - ファイル名のディレクトリ部分を抽出する basename - ファイル名からサフィックスとディレクトリを除く touch - ファイルのタイムスタンプを変更する readlink - シンボリックリンクファイルや絶対パスのファイル名を表示 wc - 文字数・単語数・行数を確認する Windowsのコマンドプロンプトの文字コードを設定 sync - メモリにバッファ中のデータをディスクに書き込む |
ワンライナーのテクニック
自己代入(||=演算子)
rubyは未定義の値を使用するとエラーが出ます。
||=演算子は値が未定義の場合に何かの値を入れる場合に使用できます。初期化とかに便利です。
mapやinject
map(collect)やinject(reduce)はEnumerableモジュールにある機能で、ArrayクラスやHashクラスなどのオブジェクトの集まりで利用することができます。
mapの場合は、各要素に渡されたブロックの処理を行い、その結果を配列として返します。全ての要素に対して何かの操作を行いたい場合にとても便利なメソッドになります。
例えば、全ての文字列オブジェクトを数値オブジェクトに変換するには以下のようにできます。
コマンド例
1 |
ruby -e 'p ["1","2","3"].map{|x| x.to_i}' |
実行結果
1 |
[1, 2, 3] |
injectはリストの畳み込み演算を行います。
つまり、最初の要素と次の要素に対してある演算を行い、その結果に対して、さらに次の要素に対しても同じ演算を行っていき、その演算を行った最終的な結果を得たい場合に利用できます。
例えば、ある数値オブジェクトの配列に対しての合計の数値を求める場合は以下のようにできます。
コマンド例
1 |
ruby -e 'p [11,22,33].inject{|result,x| result+x}' |
実行結果
1 |
66 |
mapやinjectはブロックを引数に取ります。ブロックは、&をつけることで実引数として渡すことができます。
そこにシンボルでメソッドを渡すことで、ブロックで渡される引数自身が持つメソッドを呼ぶことができます。例えば、上のmapの例は単純に以下のようになります。
コマンド例
1 |
ruby -e 'p ["1","2","3"].map(&:to_i)' |
実行結果
1 |
[1, 2, 3] |
配列の要素を変更
配列の特定の要素を変更したい場合はArray#fillが利用できます。用途としては集計後の要素を変更できます。Array#fillの構文は以下のようになります。
1 2 3 4 5 6 7 8 |
fill(obj) → self fill(obj, start) → self fill(obj, start, length) → self fill(obj, range) → self fill {|index| ... } → self fill(start) {|index| ... } → self fill(start, length) {|index| ... } → self fill(range) {|index| ... } → self |
コマンド例
1 |
ruby -e 'p [0, 55, 0, 75].fill("結果1", 0, 1).fill("結果2", 2, 1)' |
実行結果
1 |
["結果1", 55, "結果2", 75] |