日々之迷歩

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

ITが複雑で難しくなっていく様に翻弄される日々です。微力ながら共著させていただいた「シェル・ワンライナー160本ノック」をよろしくお願い申し上げます。

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

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

イベントについて

ようやく少し精神的にも余裕が出た気がする?ので、シェル芸勉強会の解答を作成しました。トークイベントの情報や問題と解答については、勉強会主催者上田さんのページをご覧ください。

b.ueda.tech b.ueda.tech

今回の勉強会は下記の本の出版を記念してのトークイベント内で行われました。なので回答も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にまとまっていました。

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をブレンドすれば意外とスッキリ解けました。

$ 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 ロング形式で出力(ゼロパディング有)