Just another Ruby porter,

〜2015年4月中旬〜


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

2015-04-11 (Sat)

13. col1.txtとcol2.txtをマージ #awk

awk万能。

% awk '{getline col2 < "col2.txt"; print $1 "\t" col2}' col1.txt

$2へ読み込むという方法もある。

% awk '{getline $2 < "col2.txt"; print}' OFS='\t' col1.txt

さらにゴルフするとprintも省略できる。

% awk 'getline $2 < "col2.txt"' OFS=\\t col1.txt

2015-04-12 (Sun)

14. 先頭からN行を出力 #シェル芸

headをsedやawkで。

% sed -n '1,10p' hightemp.txt 
% sed '1,10!d' hightemp.txt 
% awk 'NR==1,NR==10' hightemp.txt
% awk 'NR<=10' hightemp.txt

こんな感じが自然だが、元のファイルが非常に大きい場合は無駄に最後まで読んでしまう。
そこで発想を変えて、10行表示したら終了すると考える。

% sed '10q' hightemp.txt
% awk '1;NR==10{exit}' hightemp.txt

こうすれば瞬時に終了する。


2015-04-13 (Mon)

MailmanとSpamAssassinとの連携

ruby-talk MLがspam bombにまたやられてしまった。
で、SpamAssassinはどう判断してたのか確認してみると、ちゃんとspamと判断していた。

X-Spam-Flag: YES
X-Spam-Status: Yes, score=6.3 required=5.0 tests=FSL_HELO_NON_FQDN_1,
	HELO_NO_DOMAIN,RDNS_NONE,SUBJ_ALL_CAPS autolearn=disabled version=3.3.1

うーむ。From詐称でメンバーからのアドレスだとSpamAssassinの結果が無視されるのかと、
Mailman/Handlers/SpamAssassin.pyを読んでみたら、
無視じゃなくてMEMBER_BONUSだけ引かれてることがわかった。
MailmanではYESは見ずにscoreを自前で評価しているんだな。
MEMBER_BONUSのデフォルト値が2なのでscoreは4.3となり5よりも小さくなってしまう。
このあたりのぎりぎりの攻防ですり抜けてしまったようだ。

とりあえずmm_cfg.pyでMEMBER_BONUSを0にして様子見。


2015-04-14 (Tue)

今年の祝日 #シェル芸 #awk

今年の祝日が知りたくなったのでicalendarをいじってみた。

% curl -s https://www.google.com/calendar/ical/ja.japanese%23holiday%40group.v.calendar.google.com/public/basic.ics |\
  awk 'sub(/^(SUMMARY|DTSTART.*DATE):/, "")' |\
  awk -F'\r' '$0~strftime("%Y")&&getline $2' | sort
20150101 元日
20150112 成人の日
20150211 建国記念の日
20150321 春分の日
20150429 昭和の日
20150503 憲法記念日
20150504 みどりの日
20150505 こどもの日
20150506 憲法記念日 振替休日
20150720 海の日
20150921 敬老の日
20150922 国民の休日
20150923 秋分の日
20151012 体育の日
20151103 文化の日
20151123 勤労感謝の日
20151223 天皇誕生日

改行コードがCR+LFなのでCRを消すために-F'\r'としている。


2015-04-15 (Wed)

昨日の修正

lessで見ると行の途中にあるCRしか目立たないので肝心の行末を処理してなかった。
というわけで、

  awk 'sub(/^(SUMMARY|DTSTART.*DATE):/, "")' |\
  awk -F'\r' '$0~strftime("%Y")&&getline $2' | sort

の部分は

  awk 'sub(/^(SUMMARY|DTSTART.*DATE):/, "")' RS='[\r\n]+' |\
  awk '$0~strftime("%Y")&&getline $2' | sort

と修正。これでLFでもCRLFでもok。dos2unixを通してもいいが。


2015-04-16 (Thu)

Rubyで偶数番目を抜き出す

with_indexを使わない方法を考えていたら、こんなのを思い付いた。

% ruby -e 't=true;p [*1..11].select{t=!t}'
[2, 4, 6, 8, 10]

まあ、こんどはtが気に入らないという話になるわけだが。

cf: [Java][Ruby] 配列の偶数番目の要素を抜き出す: 遠回りするかな


2015-04-17 (Fri)

Rubyのputsとwrite(2)

twitterでputs("hoge")は"hoge"と"\n"と分割されてwrite(2)されるという指摘があった。
これはputsの挙動を考えると納得する。
putsは最後に"\n"がないときにだけ"\n"を追加する。
これをそのまま実装すると"hoge"を出力してから最後の"\n"の有無を判断し出力となる。
つまりわざわざ"hoge"+"\n"にしてから出力するような処理にはならない。
出力先がttyならunbufferedなのでwriteが2回呼ばれることになり、
ファイルならbufferされるのでたぶん1回で済む。

% strace -e write -o out.log ruby -e 'puts "hoge"'; cat out.log
hoge
write(1, "hoge", 4)                     = 4
write(1, "\n", 1)                       = 1
write(4, "!", 1)                        = 1
+++ exited with 0 +++
% strace -e write -o out.log ruby -e 'STDERR.puts "hoge"'; cat out.log
hoge
write(2, "hoge", 4)                     = 4
write(2, "\n", 1)                       = 1
write(4, "!", 1)                        = 1
+++ exited with 0 +++
% strace -e write -o out.log ruby -e 'puts "hoge"' > /dev/null; cat out.log
write(1, "hoge\n", 5)                   = 5
write(4, "!", 1)                        = 1
+++ exited with 0 +++
% strace -e write -o out.log ruby -e 'puts "hoge\n"'; cat out.log
hoge
write(1, "hoge\n", 5)                   = 5
write(4, "!", 1)                        = 1
+++ exited with 0 +++

この"!"はいったい?


2015-04-18 (Sat)

第16回春だからログ解析するぞシェル芸勉強会にUstで参加

例によってUstで参加。とりあえず準備1だけ。今回一番難しい問題と言われている。

% time zcat access_log.nasa.gz|ruby -EASCII-8BIT -F' ' -ane 'a=$F[3][1..-1].split(/[:\/]/);print a[2],{"Jul"=>"07","Aug"=>"08"}[a[1]],a[0]," ",a[3],a[4],a[5]," ",$_' >access-ruby.log
zcat access_log.nasa.gz  3.89s user 0.10s system 4% cpu 1:37.52 total
ruby -EASCII-8BIT -F' ' -ane  > access-ruby.log  96.16s user 1.24s system 99% cpu 1:37.54 total

TimeとかDateオブジェクトにしてstrftimeするとものすごく遅くなるので、JulとAugしかない点を利用する。
いまいち。
perlでもやってみようと思ったら、-F' 'の挙動がよくわからない。

-Fpattern
     specifies the pattern to split on for -a. The pattern may be surrounded by "//", "", or '', otherwise it
     will be put in single quotes. You can't use literal whitespace in the pattern.

使えないと言われてもねえ。

% echo 'a b' | perl -F' ' -e 'print join(":",@F)'
a: :b:

空文字でsplitされるようで。本当に使えないようだ。\sじゃ意味が違うし。

同じことをawkで。

% time zcat access_log.nasa.gz|awk -F' ' '{split(substr($4,2,21),a,/[:\/]/);h["Jul"]="07";h["Aug"]="08";print a[3]h[a[2]]a[1],a[4]a[5]a[6],$0}' >access-awk.log                   
zcat access_log.nasa.gz  3.75s user 0.08s system 22% cpu 16.681 total
awk -F' '  > access-awk.log  14.53s user 0.68s system 91% cpu 16.683 total

実はgawkのほうが断然速い。この場合LANG=Cはあまり関係ない。mawkにするともっと速くなる。

% time zcat access_log.nasa.gz|mawk -F' ' '{split(substr($4,2,21),a,/[:\/]/);h["Jul"]="07";h["Aug"]="08";print a[3]h[a[2]]a[1],a[4]a[5]a[6],$0}' >access-awk.log
zcat access_log.nasa.gz  2.05s user 0.05s system 38% cpu 5.477 total
mawk -F' '  > access-awk.log  4.81s user 0.66s system 66% cpu 8.211 total

つづく。


2015-04-19 (Sun)

引き続き準備1 sed編

まだ引っ張るわけで。今回はsedで。

% time zcat access_log.nasa.gz | sed -r 's,(.*\[(..)/(...)/(....):(..):(..):(..).*),\4\3\2 \5\6\7 \1,;s/^(....)Jul/\107/;s/^(....)Aug/\108/' > access-sed.log
zcat access_log.nasa.gz  4.42s user 0.08s system 6% cpu 1:09.81 total
sed -r  > access-sed.log  67.95s user 0.85s system 97% cpu 1:10.40 total

意外にawkよりも遅いというか、実は大抵GNU sedはGNU awkよりも遅い。
-rを使わなくても書けるが、速度に大した差はないのでわかりやすい例を挙げた。
\107と書くと107番目になるわけではなく、
実は1から9までの1桁しか有効ではないので、特に問題はない。
つまり()を10個以上書いても参照しようがない。


2015-04-20 (Mon)

今日も準備1 perl編

実は昨日のsed scriptはほとんどperl scriptと言ってもいいぐらい似ている。
そのままではPerlだと\107が8進数を意味するのでまずい。
\108は8が8進数ではないので\10と8つまり\b8という意味なる。
これを回避する${1}07,${1}08を使えばいい。

% time zcat access_log.nasa.gz | perl -pe 's,(.*\[(..)/(...)/(....):(..):(..):(..).*),\4\3\2 \5\6\7 \1,;s/^(....)Jul/${1}07/;s/^(....)Aug/${1}08/' > access-perl3.log
zcat access_log.nasa.gz  2.87s user 0.07s system 15% cpu 19.598 total
perl -pe  > access-perl3.log  18.89s user 0.72s system 88% cpu 22.246 total

結構速い。sedでs///するならperlでs///したほうがまし。ほとんど同じだし。


<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!