読者です 読者をやめる 読者になる 読者になる

日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です

第17回シェル芸勉強会回答例

ということで、第17回シェル芸勉強会は、ジュンク堂を乗っ取ってのトークイベントの中で行われたようだ。Ustream配信はされていたが、今回は仕事でテンパっていて参加出来ず・・・

ようやく少し精神的にも余裕が出た気がする?ので、シェル芸勉強会の回答をば。問題と回答については、USP友の会会長様のページをご覧あれ。

【問題のみ】第17回ジュンク堂はシェル芸が乗っ取った勉強会 – 上田ブログ

【問題と解答】第17回ジュンク堂はシェル芸が乗っ取った勉強会 – 上田ブログ

今回の勉強会は下記の本の出版を記念してのトークイベント内で行われた。なので回答もAWKを多用すべきなんろうが、あんまり使ってないのでご容赦を・・・awkを使った例は、上記会長の解答例をご覧あれ。awkは処理速度も速いし色々便利。

www.amazon.co.jp

www.amazon.co.jp

トークイベントについてはこちらのTogetterにて。

togetter.com

下記解答例の実行環境は、MacでOSX Yosemite、HomebrewでGNU grep(ggrep)とrbenv、Open usp Tukubai。Rubyはruby 2.2.2p95。

Q1

第一フィールドをキーにして、同じキーで横へ並べる。

$ cat data1
a 1
b 4
a 2
a 3
b 5

Tukubai使うと超簡単に・・・

$ cat data1 | sort | yarr num=1
a 1 2 3
b 4 5

次にJSON形式で出力。上記のTukubai芸からのRuby芸。Rubyの配列連結を使えば割と簡単?

$ cat data1 | sort | yarr num=1 |
 ruby -alne 'BEGIN{a=[]};a<<$F[0]+":["+$F[1..-1]*","+"]";END{puts "{"+a*","+"}"}'
{a:[1,2,3],b:[4,5]}

Q2

データの中で同じ行のものを探し出し、行番号を出力。

$ cat data
0.5937836043 0.4644710001
0.3637036697 0.5593602512
0.5655269331 0.6793148112
0.7804610574 0.2905477797
0.3637036697 0.5593602512

得意技になりつつある、GNU grepのフィルタモードと、bashのProcess Substututionの合わせ技。これにTukubaiをブレンドすれば意外とスッキリ。Process Substututionはチョット反則な気がするが、まあいいよね?

$ cat data | sort -k2,3 | uniq -u |
 ggrep -v -f - <(juni data) | self 2/NF 1 | yarr num=2
0.3637036697 0.5593602512 2 5

【追記】もっと簡単にこんなのでもよかった。

$ cat data | sort | uniq -d | ggrep -nf - data 
2:0.3637036697 0.5593602512
5:0.3637036697 0.5593602512

Q3

JSON形式のデータについて、キーに対応した配列内の数値を合計。

$ cat json
{"a":[1,2,3],"b":[4,5]}

1行1レコード空白区切りにしてしまえばこっちものでゴザル。

$ cat json | grep -o '"[ab]":\[[^]]*\]' | tr '":[],' ' ' |
 ysum num=1 | awk '{print $1,$NF}'
a 6
b 9

Ruby芸。JSON ModuleとArray#inject使えば簡単になっちゃうので、問題の意図に反している気が・・・

$ cat json |
 ruby -r json -ne 'JSON.load($_.chomp).each{|l| puts "#{l[0]} #{l[1].inject(:+)}"}'
a 6
b 9

Q4

IPv6ゼロパディングの闇にトライなお題。ちなみにこのお題、シェルプログラミング実用テクニックにも記載があるので、興味がある方はご購入をば。

え〜ゴメンナサイゴメンナサイ、Rubyで反則使ってゴマカシ・・・・

$ echo 2001:db8::9abc |
 ruby -r 'ipaddr' -ne 'puts IPAddr.new($_.chomp).to_string'
2001:0db8:0000:0000:0000:0000:0000:9abc

$ echo ::1 |
 ruby -r 'ipaddr' -ne 'puts IPAddr.new($_.chomp).to_string'
0000:0000:0000:0000:0000:0000:0000:0001

おまけで逆変換。

$ echo '2001:0db8:0000:0000:0000:0000:0000:9abc' |
 ruby -r 'ipaddr' -ne 'puts IPAddr.new($_.chomp).to_s'
2001:db8::9abc

$ echo 0000:0000:0000:0000:0000:0000:0000:0001 |
 ruby -r 'ipaddr' -ne 'puts IPAddr.new($_.chomp).to_s'
::1

Q4のRuby芸のポイントはこちら。

  • IPAddr#to_s ショート形式で出力(ゼロパディング無)
  • IPAddr#to_string ロング形式で出力(ゼロパディング有)