Just another Ruby porter,

〜2016年6月中旬〜


<Older(,) | Newer(.)> | Recent(/)>> | RDF

2016-06-11 (Sat)

jqで

anagol的にはつい-sまでしちゃうが、それは不要。

% jot -r 10 1 100 | xargs -n 5 | jq -R -r 'split(" ")|map(tonumber)|sort|@sh'                          
6 29 34 59 62
27 30 67 80 82

sort_byを使う方法も。

% jot -r 10 1 100 | xargs -n 5 | jq -R -r 'split(" ")|sort_by(tonumber)|join(" ")'
2 5 9 32 90
1 7 76 87 95

2016-06-12 (Sun)

ifconfig.meの代替

というわけでいろいろ探してみた。

% for i in inet-ip.info ifconfig.io ifconfig.es globalip.me ipcheck.ieserver.net ifconfig.co ipv4bot.whatismyipaddress.com httpbin.org/ip;do echo -n "$i: "; /usr/bin/time -f '%E %C' curl -s $i > /dev/null; done 2>&1 | sort -k2,2 | column -t
globalip.me:                    0:00.23  curl  -s  globalip.me
ifconfig.io:                    0:00.25  curl  -s  ifconfig.io
ipv4bot.whatismyipaddress.com:  0:00.28  curl  -s  ipv4bot.whatismyipaddress.com
ipcheck.ieserver.net:           0:00.36  curl  -s  ipcheck.ieserver.net
inet-ip.info:                   0:00.45  curl  -s  inet-ip.info
httpbin.org/ip:                 0:00.46  curl  -s  httpbin.org/ip
ifconfig.es:                    0:00.61  curl  -s  ifconfig.es
ifconfig.co:                    0:00.64  curl  -s  ifconfig.co

どれでも同じようなもんだけど、httpbin.org/ipはjson形式だったりするので注意。


2016-06-13 (Mon)

jq 1.4と1.5

シェル芸で使いたい jqイディオム - Qiitaを見ててあれと思った。

printfコマンドで最後の改行を削っておかないと、行配列の最後に空の要素が入ってしまう

そんなことないような。

% echo foo | jq -R -s 'split("\n")'
[
  "foo"
]

ああ、jq 1.5だとsplitの挙動が違うのか。

% echo foo | jq-1.5 -R -s 'split("\n")'
[
  "foo",
  ""
]

これはうっとうしいかも。


2016-06-14 (Tue)

jqでCSVの読み込み

シェル芸で使いたい jqイディオム - Qiita
CSVの読み込みで全体を配列としないならこういう方法もある。
まず-sを削除。改行でsplitする必要がなくなりmapも不要になる。
しかも最後の改行はつかなくなるので前段の処理も不要。

% echo $'foo1,bar1,hoge1\nfoo2,bar2,hoge3' | jq-1.4 -R 'split(",") | {"fld1": .[0], "fld3": .[2]}'
{
  "fld1": "foo1",
  "fld3": "hoge1"
}
{
  "fld1": "foo2",
  "fld3": "hoge3"
}
% echo $'foo1,bar1,hoge1\nfoo2,bar2,hoge3' | jq-1.5 -R 'split(",") | {"fld1": .[0], "fld3": .[2]}'
{
  "fld1": "foo1",
  "fld3": "hoge1"
}
{
  "fld1": "foo2",
  "fld3": "hoge3"
}

1.4でも1.5でも結果は同じ。


2016-06-15 (Wed)

pipeでの$(cat)の挙動

またまた シェル芸で使いたい jqイディオム - Qiitaの登場で恐縮ではあるけど、CSVの読み込みで最後の改行削除で、

cat sample.csv | printf %s "$(cat)"

していた。これはbashでは動くがzshでは動かない。

% echo foo | printf %s "$(cat)" 
cat: -: 入力/出力エラーです

どうもpipe処理よりも先にコマンド置換が行なわれるようで。
というわけで後で評価されるようにしてあげればzshでも動く。

% echo foo | { printf %s "$(cat)" } | od -c
0000000   f   o   o
0000003
% echo foo | ( printf %s "$(cat)" ) | od -c
0000000   f   o   o
0000003

2016-06-16 (Thu)

slackのcustom slashコマンド

AWS Lambdaのblueprintに従うとslackにcustom slashコマンドが追加されることになる。
これが曲者でslashコマンドって結構使い辛い。
まずecho backがない。何を打ったか記録に残らない。
まあそれなら応答に入力も含めればよさげだが、
なぜかコマンドを実行した自分にしか表示されない。
というわけでこれを利用してchatopsはちょっと無理がある。


2016-06-17 (Fri)

slackでchatops

slash commandだと無理があるならどうすればいいか。 実はOutgoing WebHooksを使えばほとんど同じことができる。
こちらはチャンネル指定もできるし、"/"をつける必要もない。
もちろん普通のメッセージになるのでecho backもするし、
応答は自分だけじゃなくそのまま普通のbotoのメッセージとして処理される。
ちょっとquery parameterが違うだけなのでblueprintからの変更も少ない。
完璧だ。


2016-06-18 (Sat)

第23回シェル芸勉強会に参加

【問題】第23回梅雨でモワッとしたシェル芸勉強会 – 上田ブログ
というわけで梅雨とは思えない暑さの中行ってきた。
今回はオープンなデータを扱うawkまつりだった。
最大の敵はファイル名の長さだった。twitter的には非常につらい。

_ Q1:

これは準備。YYYYMM 上陸頻度という形式。
後々の問題のためにはYYYY MMのように空白があったほうがよかったいう意見がちらほら。

_ Q2 年ごとの台風の上陸頻度の確認:

年ごとなので上位4文字をキーにして頻度を集計。
CSVのほうは上陸してない年は0ではなく空文字なので、
$NF+0しておく必要がある。+$NFでもいい。
cmpなので何も表示されなければok。

% awk '{h[substr($1,1,4)]+=$2}END{for(i in h)print i,h[i]}' monthly_typhoon|sort|cmp - <(awk -F, 'NR>1{print $1,+$NF}' landing.csv)

_ Q3 各月の台風上陸確率:

月ごとなので年は不要。ここでも+することで0-prefixを削除している。

% awk '$2{m[+substr($1,5)]++}END{for(i=1;i<=12;i++)printf "%2d %5.2f%%\n", i,m[i]*100/NR*12}' monthly_typhoon
 1  0.00%
 2  0.00%
 3  0.00%
 4  1.54%
 5  3.08%
 6 13.85%
 7 40.00%
 8 63.08%
 9 63.08%
10 20.00%
11  1.54%
12  0.00%

_ Q4 各年で最初に台風が上陸した月を抽出し、何月が何回だったか集計:

landing.csvを使うとこんな感じ。-F,することでNFが,の数になり、それが最初の月になる。

% sed 's/,[1-9].*//' landing.csv | awk -F, 'NR>1&&NF<14{print NF}'|sort -n|uniq -c
      1 4
      2 5
      9 6
     21 7
     19 8
      7 9
      2 10

monthly_typhoonだったらこんな感じ。また+だ。

% awk '$2&&!a[substr($1,1,4)]++{print +substr($1,5)}' monthly_typhoon|sort -n|uniq -c 
% sed 's/\B/ /4' monthly_typhoon | awk '$3&&!a[$1]++{print +$2}'|sort -n|uniq -c

_ Q5 台風が上陸しなかった年を抽出:

landing.csvを使うのは禁止。
xargsを使い1年を1行にして、行頭のだけ残してYYYYMM を削除。
YYYY01 000000000000が消せればそれが上陸しなかった年。

% xargs -n24 < monthly_typhoon | sed -n  's/ [0-9]\{6\} //g;s/01 0*$//p'
1984
1986
2000
2008

_ Q6 各区で何件ずつレコードがあるか確認:

ひねりなし。

% cut -f1 -d' ' hittakuri|sort|uniq -c 
     56 大阪市中央区
      9 大阪市住之江区
     29 大阪市住吉区
     53 大阪市北区
     23 大阪市城東区
      7 大阪市大正区
     20 大阪市天王寺区
     33 大阪市平野区
      8 大阪市旭区
     22 大阪市東住吉区
     18 大阪市東成区
     17 大阪市東淀川区
      1 大阪市此花区
     22 大阪市浪速区
     31 大阪市淀川区
      6 大阪市港区
     31 大阪市生野区
      9 大阪市福島区
     28 大阪市西区
     37 大阪市西成区
      8 大阪市西淀川区
     15 大阪市都島区
     19 大阪市阿倍野区
      6 大阪市鶴見区

_ Q7 各区の人口当たりのひったくり件数のランキング:

population_h27sepをpという連想配列に読み込む。
引数にf=1を挟むことでフラグとして使える。
-(標準入力)を読み込む前にf=1になる。

% cut -f1 -d' '  hittakuri|sort|uniq -c|awk '!f{p[$1]=$2}f{printf "%7.3f%% %s\n", $1*100/p[$2],$2}' population_h27sep f=1 -|sort -nr
  0.059% 大阪市中央区
  0.045% 大阪市北区
  0.034% 大阪市西成区
  0.034% 大阪市浪速区
  0.031% 大阪市西区
  0.027% 大阪市天王寺区
  0.024% 大阪市生野区
  0.022% 大阪市東成区
  0.019% 大阪市住吉区
  0.018% 大阪市阿倍野区
  0.018% 大阪市淀川区
  0.017% 大阪市東住吉区
  0.017% 大阪市平野区
  0.015% 大阪市都島区
  0.014% 大阪市城東区
  0.013% 大阪市福島区
  0.010% 大阪市東淀川区
  0.010% 大阪市大正区
  0.009% 大阪市旭区
  0.008% 大阪市西淀川区
  0.007% 大阪市港区
  0.007% 大阪市住之江区
  0.005% 大阪市鶴見区
  0.001% 大阪市此花区

_ Q8 同一住所で同日に2件以上ひったくりが起こった場合について、その住所と日付を出力:

cutでもawkでもいいと思うが、cutのほうが指定が簡単。

% cut -d' ' -f1-3,8-10 hittakuri|sort|uniq -d
大阪市北区 曾根崎 2丁目付近 2015年 4月 13日
大阪市北区 角田町 付近 2015年 11月 4日
大阪市淀川区 十三本町 1丁目付近 2015年 4月 16日

_ Q9 ひったくりの手段とその成功率:

既遂が成功で手段が自転車とか。
/既遂/だとむだに0のときも足してるが場合分けしてないのでb[$7]++もいっしょに書ける。

% awk '{a[$7]+=/既遂/;b[$7]++}END{for(i in a)printf "%f %s\n", a[i]/b[i],i}'  hittakuri | sort -nr 
0.954225 自動二輪
0.942308 徒歩
0.920530 自転車
0.904762 自動車


2016-06-19 (Sun)

BOMを消す

nkfじゃなくても3バイト削るだけなのでBOMを消す方法はいろいろある。

tail -c +4
dd bs=1 skip=3
sed '1s/^\xEF\xBB\xBF//'
LANG=ja_JP.UTF-8 sed '1s/^.//'
LANG=C sed '1s/^...//'

LANGがja_JP.UTF-8ならBOMも1文字と見做される。


2016-06-20 (Mon)

Q1をjqで解く

その前に一昨日の日記にQ1の解を書いてなかった。

% awk -F, 'NR>1{for(i=2;i<NF;i++)printf "%d%02d %d\n",$1,i-1,$i}' landing.csv > monthly_typhoon
% head monthly_typhoon                                                                          
195101 0
195102 0
195103 0
195104 0
195105 0
195106 0
195107 1
195108 0
195109 0
195110 1
% tail monthly_typhoon
201503 0
201504 0
201505 0
201506 0
201507 2
201508 1
201509 1
201510 0
201511 0
201512 0

jqでも無理をすればなんとかなるようで。

% jq -R -r 'split(",")|[.[0]+(. as $a|range(1;13)|"0\(.) "[-3:]+$a[.])|sub(" $";" 0")]|join("\n")|select(test("^\\d"))' landing.csv > monthly_typhoon

肝はrange(1;13)|"0\(.) "[-3:]の部分で、"%02d "を意味している。

% jq -n -c 'range(1;13)|"\(.) "'
"1 "
"2 "
"3 "
"4 "
"5 "
"6 "
"7 "
"8 "
"9 "
"10 "
"11 "
"12 "
% jq -n -c 'range(1;13)|"0\(.) "[-3:]'
"01 "
"02 "
"03 "
"04 "
"05 "
"06 "
"07 "
"08 "
"09 "
"10 "
"11 "
"12 "

それをRubyで表現するとこんな感じ。

% ruby -anF, -e 'puts (1..12).map{|i|$F[0] + "%02d "%i + $F[i]}.map{|i|i.sub(/ $/, " 0")}.select{|x|x=~/^\d/}' landing.csv > monthly_typhoon

<Older(,) | Newer(.)> | Recent(/)>> | RDF


WWW を検索 jarp.does.notwork.org を検索

わたなべひろふみ
Key fingerprint = C456 1350 085F A320 C6C8 8A36 0F15 9B2E EB12 3885
Valid HTML 4.01!