第17回シェル芸勉強会解答例
ということで、第17回シェル芸勉強会は、ジュンク堂を乗っ取ってのトークイベントの中で行われたようです。Ustream配信はされていたが、今回は仕事でテンパっていて参加出来ず・・・
イベントについて
ようやく少し精神的にも余裕が出た気がする?ので、シェル芸勉強会の解答を作成しました。トークイベントの情報や問題と解答については、勉強会主催者上田さんのページをご覧ください。
今回の勉強会は下記の本の出版を記念してのトークイベント内で行われました。なので回答もAWKを多用すべきなんでしょうが、あんまり使ってないのでご容赦を・・・awkを使った例は、出題者上田さんの解答例をご覧ください。awkは処理速度も速いし色々便利です。
http://www.amazon.co.jp/シェルプログラミング実用テクニック-Software-Design-plus-上田/dp/4774173444www.amazon.co.jp
http://www.amazon.co.jp/AWK実践入門-Software-Design-plus-中島/dp/477417369X/ref=pd_bxgy_14_img_ywww.amazon.co.jp
トークイベントについてはこちらのTogetterにまとまっていました。
勉強会開始
下記解答例の実行環境は、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をブレンドすれば意外とスッキリ解けました。
$ 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 ロング形式で出力(ゼロパディング有)