Just another Ruby porter,

〜2014年7月上旬〜


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

2014-07-01 (Tue)

findでサイズが0のファイルをマークする

-printfでサイズを表示するようにして、sedなりで変更するという方法が一般的だと思うが、
findだけで可能なのかやってみた。

準備。

% mkdir tmp
% repeat 9 echo foo > tmp/$[++i].txt
% touch tmp/0.txt
% ls -l tmp
合計 36
-rw-r--r-- 1 eban eban 0 2014-07-01 23:23:59 0.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 1.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 2.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 3.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 4.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 5.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 6.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 7.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 8.txt
-rw-r--r-- 1 eban eban 4 2014-07-01 23:23:52 9.txt

0.txtだけがサイズ0。頭に@をつけるだけなら

% find tmp -size 0 -printf @ -print
@tmp/0.txt

でいいわけだが、これだと他のファイルが表示されない。
そこで-trueだ。なんの意味があるんだと思っていたが、こんな使い途が。

% find tmp -type f \( -size 0 -printf @ -or -true \) -print
tmp/7.txt
tmp/9.txt
tmp/8.txt
tmp/4.txt
tmp/2.txt
tmp/6.txt
tmp/3.txt
tmp/1.txt
@tmp/0.txt
tmp/5.txt

-or -trueで強制的に真にする。


2014-07-02 (Wed)

tmuxのsynchronize-panes

複数のpaneへ同時入力する設定。
これめちゃめちゃ便利なんだけど、トグル動作させたい。
showw -v synchronize-panesで現在の状態がわかるので、

bind e if 'test `tmux showw -v synchronize-panes` = on' 'setw synchronize-panes off' 'setw synchronize-panes on'

とすればPREFIX eでいけるかと思ったら、なんとon/offを指定しなければ最初からトグルだった。

bind e setw synchronize-panes

でokだ。


2014-07-03 (Thu)

6月のspam

220通ほど。平和が戻った。

bashで62進数

62進数は 短縮URLでも使われていて、マッピングさえなんとかすればいける。
一方bashでも0-9,a-z,A-Zで62進数も扱える。
man bashによると@,_と合わせて64進数まであり。
62進でe9aを10進に変換するなら簡単。ただし、短縮URLの例ではマッピングが違うので変換が必要。
a-z,A-Z,0-9という順番なので

% bash -c 'echo $[62#`tr a-zA-Z0-9 0-9a-zA-Z <<< e9a`]'
19158

となる。むしろ逆変換のほうが欲しいが、さすがにそれはbashにはない。
zshにはあるが大文字小文字を無視するので36進数まで。


2014-07-04 (Fri)

baseNをなんとなく作ってみた

base62のつもりだったが、テーブルの大きさ次第に気づき、Nになった。

#! /bin/bash

tbl=({0..9} {a..z} {A..Z} + /)
N=${#tbl[@]}
z=${tbl[0]}

base(){
  local i=$1
  local b=
  while ((i > 0)); do
    b=${tbl[i % N]}$b
    i=$[i / N]
  done
  result=${b:-${tbl[0]}}
}

for ((i=0; i < $1; i++)); do
  base $i
  a="$z$z$z"${result}
  b=${a%????}
  echo "${a#$b} $i"
done

0の場合を見落としていて、とってつけたような対応になっている。
tblを差し替えればいくらでも。連続する文字は{..}が使えるので楽。


2014-07-05 (Sat)

right timeが通らない

40バイトという記録があるが、

TZ=right/UTC xargs -i date -d@{} +%F\ %T

これって

sed s/^/@/|TZ=right/UTC date -f- +%F\ %T

でもよさげだなあと試してみるも通らない。
サイズは変わらないので通っても通らなくてもいいんだが、
3番目でなぜか数秒ずれるものがある。
どういうことだと元の解でもやってみると、なんとだめだった。
Rubyのもだめだ。
2010年以降が全部ずれてる。
うるう秒の設定ってなんか変わったんだっけ?


2014-07-06 (Sun)

巨大なデータをgrepする

昨日作った64進と10進で1000万行ほどデータを作り、
奇数行の64進だけ抜き出したキーをファイルにしてgrepする。
遅いのでperlで書き直した。

% time perl base.pl 10000000 > data.txt 
% awk 'NR%2{print $1}' data.txt | sort > key.txt
% wc -l data.txt key.txt
 10000000 data.txt
  5000000 key.txt
 15000000 合計
% head data.txt key.txt
==> data.txt <==
0001 1
0002 2
0003 3
0004 4
0005 5
0006 6
0007 7
0008 8
0009 9
000a 10

==> key.txt <==
0++/
0++1
0++3
0++5
0++7
0++9
0++B
0++D
0++F
0++H

やりたいのはkey.txtの内容でgrepすることだ。
forやwhil readで1個なり数個なりでgrepするのはものすごく時間がかかる。
かといってgrep -f key.txt data.txtは入力を受け付けなくなるぐらい重くなる。
それに+を使っちゃったのでエスケープ処理も必要になる。
じゃあfgrep -f key.txt data.txtならいいかというと、
実は2番目のフィールドの余計なものにマッチする。

% time fgrep -f key.txt data.txt | wc -l
9297500
fgrep -f key.txt data.txt  9.59s user 0.33s system 99% cpu 9.968 total

key.txtが500万行ある割には結構速い。10秒ほどでできてしまう。

% time fgrep -f <(sed 's/$/:/' key.txt) <(sed 's/ /: /' data.txt) | sed 's/://' | wc -l
5000000
fgrep -f <(sed 's/$/:/' key.txt) <(sed 's/ /: /' data.txt)  8.22s user 0.30s system 77% cpu 11.045 total

まあ、こんな小細工が必要になる。

それとは別にawkを使う手もある。

% time awk 'NR==FNR{map[$1];next}$1 in map' key.txt data.txt | wc -l
5000000
awk 'NR==FNR{map[$1];next}$1 in map' key.txt data.txt  6.96s user 0.24s system 99% cpu 7.204 total

これはkey.txtを全部連想配列のmapに入れてdata.txtの$1だけを見て判断している。
共通フィールドを抜き出すときによく使われる。
NR==FNRで最初のファイルのときだけ真になるのでkey.txtだけmapへ入れられる。
awkは参照するだけでエントリーが作られるのでmap[$1]=1とかしなくてもいい。
存在確認はinを使うのが正しい。つづく。


2014-07-07 (Mon)

grepの代わりにsort,uniqで代用

どういうことかというとkey.txtとdata.txtを合わせてsortする。
欲しいのはダブったところなので、uniq -dで取り出せばいい。
ただそのままだと2番目のフィールドが邪魔なので-w4をつけてkeyだけを対象にする。
-wの場合は最初に現われたものが残るので

0001 1
0001

という具合に並べておけばいい感じにgrepと同じ結果になる。
以上まとめると

% time sort -r key.txt data.txt | uniq -d -w4 > out
sort -r key.txt data.txt  5.18s user 0.42s system 237% cpu 2.360 total

とすればいい。しかも結構速い。
これだとawkのようにkey.txtの内容をメモリに全部取り込むこともないので、
たぶんもっと巨大なデータになっても対応できるはず。

一応チェック。

% grep '[02468]$' out
% wc -l out
5000000 out

さらにつづく。実はまだ方法はある。


2014-07-08 (Tue)

grepの代わりにjoin

joinというと2つのファイルを共通フィールドで結合するという目的使われる。
フィールドに差異があっても共通な部分しか表示されない。
ってことはそれってgrepだよね。

% time join key.txt <(sort data.txt) > out2 
join key.txt <(sort data.txt) > out2  1.78s user 0.13s system 68% cpu 2.782 total

これも結構速い。アルゴリズム的にはマージソートと同じようなもんだからか。
全部読み込んでから処理するわけではないのでメモリも気にする必要はない。


2014-07-09 (Wed)

calibreを更新したらebook-convertが遅くなった

そもそもdot by dotで画像は変換済みなのでebook-convertを使う必要もなく、
epubへ変換できればいいんだよなあ。
htmlとか画像数だけ作ればいいだけだし自前で作るか。


2014-07-10 (Thu)

convertのresize

convertの-resizeにはいろんなgeometry表現で指定できるが、
後ろにつく記号の意味をすぐ忘れるので備忘録。
まずはなにもつけない場合:

% convert -size 100x100 xc: -resize 150x200 info:
xc: XC 150x150 150x150+0+0 16-bit DirectClass 0.010u 0:00.009
% convert -size 100x100 xc: -resize 200x150 info:
xc: XC 150x150 150x150+0+0 16-bit DirectClass 0.010u 0:00.070

これは指定したgeometryに最大限収まる大きさになる。
150x200とか200x150になるわけではなく、縦横比は保存される。
強制的に200x150にするには!を使う。

% convert -size 100x100 xc: -resize 150x200\! info:
xc: XC 200x150 150x200+0+0 16-bit DirectClass 0.020u 0:00.000

注意しないといけないのはwidthかheightのどちらかを省略した場合:

% convert -size 100x100 xc: -resize 200x info:
xc: XC 200x200 200x200+0+0 16-bit DirectClass 0.020u 0:00.010
% convert -size 100x100 xc: -resize x200 info:
xc: XC 200x200 200x200+0+0 16-bit DirectClass 0.010u 0:00.000

のように縦横比は保存されるが、はみ出てしまうかもしれない。


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