Just another Ruby porter,

〜2015年1月下旬〜


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

2015-01-21 (Wed)

sedでも対応してみる

awkの$3は3つあることを確認している。
つまりsedでも3個あることを確認すればいい。
フィールドが3個ということは区切りは2個なので/ .* /でok。

% seq 100|xargs -n3|sed '/ .* /s/[^ ]*$/Fizz/'|xargs -n5|sed '/ .* .* .* /s/[0-9]*$/Buzz/'|xargs -n1

ちょっと不恰好だけど、正規表現で条件を書けばいける。


2015-01-22 (Thu)

readの挙動

while read lineで読んでいるときに最終行に改行がないとループを抜けてしまう。
だが、read自身はちゃんとlineへ反映させているのであった。

% bash -c 'echo -n foo | while read line; do echo $line; done'                  
% bash -c 'echo -n foo | { while read line; do echo $line; done; echo $line; }'
foo

つまりwhileの条件でreadが偽だったら$lineの中身を見ればいい。たとえば

% bash -c 'echo -n foo | { while read line || [ -n "$line" ]; do echo $line; done; }'
foo

みたいに。


2015-01-23 (Fri)

面接官 「1~250までの数字がある。1つだけ抜けてる数字がある時、どうやってその数字を探し出しますか?」 をcommで解く #シェル芸

これはdiffでもいいけどcommとかjoinを使うと簡単。

% seq 250 | sed 128d | sort > nums
% seq 250 | sort | comm -23 - nums      
128

1つだけじゃなく何個でもok。

% seq 250 | sed '50d;128d;200d' | sort > nums
% seq 250 | sort | comm -23 - nums           
128
200
50
% seq 250 | sort | join -v1 - nums
128
200
50

commやjoinはあらかじめsortしておく必要がある。


2015-01-24 (Sat)

commとjoinの違い

commは共通部分を抜き出すのに使うが、複数並んでいても1個しか相手にされない。
一方joinは並んでいると全部共通部分とみなす。これは何を意味するかというとgrepの代わりに使える。

% printf '1\n2\n2\n2\n3\n' | comm -12 - <(echo 2)
2
% printf '1\n2\n2\n2\n3\n' | join - <(echo 2)
2
2
2

grepの代わりになって何がうれしいんだという話ではあるが。


2015-01-25 (Sun)

例の250の問題をgrepで #シェル芸

よく考えてみたらcommを使わなくてもgrepでいけるのであった。

% seq 250 | sed 128d > nums      
% seq 250 | grep -xv -f nums
128
% seq 250 | sed '50d;128d;200d' > nums       
% seq 250 | grep -xv -f nums
50
128
200

-xは強制的に行全体でPATTERNの一致処理を行うという意味。^と$がつく感じ。
この場合は-wでもいいが、空白とか含まれる場合は-xが必須となる。
sortする必要もないし、こっちのほうがいいかも。


2015-01-26 (Mon)

250じゃなくて10万だとOOM Killer

例の問題はgrepで250ぐらいならなんともないが、
10万ぐらいになると8GBあってもメモリが足りなくなる。

% seq 100000 | sed 5000d > nums100K     
% time seq 100000 | grep -xv -f nums100K
zsh: broken pipe  seq 100000 | 
zsh: killed       grep -xv -f nums100K
seq 100000  0.00s user 0.00s system 0% cpu 19:12.16 total

/var/log/syslogを見るとOOM Killerに殺されていた。

Jan 26 23:07:41 m kernel: [ 1572.506071] Out of memory: Kill process 7702 (grep) score 922 or sacrifice child
Jan 26 23:07:41 m kernel: [ 1572.506073] Killed process 7702 (grep) total-vm:15207580kB, anon-rss:7427400kB, file-rss:0kB

こういうときはどうするかというとfgrepを使う。

% time seq 100000 | fgrep -xv -f nums100K 
5000
seq 100000  0.00s user 0.00s system 1% cpu 0.191 total
fgrep -xv -f nums100K  0.06s user 0.00s system 33% cpu 0.194 total

まじかっていうほどあっさり通る。正規表現がいかにメモリを食うかがわかる例。


2015-01-27 (Tue)

commとjoinの速度

5000万ぐらいになるとfgrepでも結構苦しくなる。

% seq 50000000 | sed 5000d > nums50M
% time seq 50000000 | fgrep -xv -f nums50M 
5000
seq 50000000  0.99s user 0.25s system 1% cpu 1:55.80 total
fgrep -xv -f nums50M  113.18s user 2.62s system 99% cpu 1:56.03 total

2分近くかかっている。少しでも速く実行したいならjoinやcommを使う。

% time seq 50000000 | sort | join -v1 - <(sort nums50M)
5000
seq 50000000  0.77s user 0.13s system 7% cpu 12.189 total
sort  15.41s user 1.81s system 35% cpu 48.196 total
join -v1 - <(sort nums50M)  8.13s user 0.28s system 17% cpu 48.195 total
% time seq 50000000 | sort | comm -23 - <(sort nums50M)
5000
seq 50000000  0.81s user 0.14s system 9% cpu 9.953 total
sort  15.62s user 1.96s system 41% cpu 42.238 total
comm -23 - <(sort nums50M)  4.22s user 0.28s system 10% cpu 42.237 total

2倍以上速い。実はほとんどソートしてる時間だったりする。
あらかじめソートしといていいなら10秒かからない。

% seq 50000000 | sort > seq50Ms
% seq 50000000 | sed 5000d | sort > nums50Ms
% time join -v1 seq50Ms nums50Ms                  
5000
join -v1 seq50Ms nums50Ms  6.95s user 0.10s system 99% cpu 7.060 total
% time comm -23 seq50Ms nums50Ms
5000
comm -23 seq50Ms nums50Ms  3.52s user 0.11s system 99% cpu 3.633 total

grepの代わりになって実はうれしいのである。


2015-01-28 (Wed)

convertの引数の順番はやはり大事

PDFを画像にするときの定番にconvertがある。
-densityで指定しても低いままだなあとずっと思っていたが、
これも順番がものすごく大事だとわかった。
たとえば

% convert foo.pdf -density 300 foo.jpg

とかやりがちだが、これだと全然意味がない。

% convert -density 300 foo.pdf foo.jpg

のようにfoo.pdfの前に-densityを置く。-verboseをつけるとよくわかる。

% convert -verbose '残照.pdf[1]' -density 300 /tmp/foo.jpg
"gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r72x72" -dFirstPage=2 -dLastPage=2 "-sOutputFile=/tmp/magick-_Uc3SdUw-%08d" "-f/tmp/magick-qPsh2kGe" "-f/tmp/magick-fujmhwsW"
/tmp/magick-_Uc3SdUw-00000001 PNG 298x496 298x496+0+0 8-bit DirectClass 4.22KB 0.010u 0:00.000
残照.pdf[1]=>残照.pdf[1] PDF 298x496 298x496+0+0 16-bit DirectClass 0.000u 0:00.000
残照.pdf[1]=>/tmp/foo.jpg[1] PDF 298x496 298x496+0+0 16-bit DirectClass 0.000u 0:00.000

内部的にはgsが変換してるが、-r72x72となってる。つまり-density 72ということだ。
これはconvertのデフォルトの値と思われる。
ファイル名の後に-density 300を指定しても後の祭りということになる。

% convert -verbose -density 300 '残照.pdf[1]' /tmp/foo.jpg
"gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r300x300" -dFirstPage=2 -dLastPage=2 "-sOutputFile=/tmp/magick-YslpFx3t-%08d" "-f/tmp/magick-XPhLyekZ" "-f/tmp/magick-mVgnGZAu"
/tmp/magick-YslpFx3t-00000001 PNG 1240x2066 1240x2066+0+0 8-bit DirectClass 17.3KB 0.060u 0:00.060
残照.pdf[1]=>残照.pdf[1] PDF 1240x2066 1240x2066+0+0 16-bit DirectClass 0.000u 0:00.000
残照.pdf[1]=>/tmp/foo.jpg[1] PDF 1240x2066 1240x2066+0+0 16-bit DirectClass 16.4KB 0.040u 0:00.039

これで-r300x300になった。


2015-01-29 (Thu)

libcを検索してどうする

GHOSTが話題だが このページにあるglibcを使ってるプロセスを探す方法はつっこまずにはいられない。

$ lsof | grep libc | awk '{print $1}' | sort | uniq

コメントでawkだのsort -uを使えば短くなるとかあるのはまあお約束として、問題はlibcで検索してるところ。

% lsof |grep -o 'libc.*' | sort -u
libc-2.19.so
libc.mo
libcairo-gobject.so.2.11301.0
libcairo.so.2.11301.0
libcanberra-0.30/libcanberra-pulse.so
libcanberra-gtk-module.so
libcanberra-gtk.so.0.1.9
libcanberra-gtk3-module.so
libcanberra-gtk3.so.0.1.9
libcanberra.so.0.2.5
libcap-ng.so.0.0.0
libcap.so.2.24
libcgmanager.so.0.0.0
libcom_err.so.2.1
libcpufreq.so.0.0.0
libcpugraph.so
libcroco-0.6.so.3.0.1
libcrypt-2.19.so
libcrypto.so.1.0.0
libcups.so.2
libcurl.so.4.3.0

libcで始まるライブラリはいっぱいあるわけで。

というよりもすべてのプロセスはlibcに依存していると言っていいわけで、
libcで検索すること自体ナンセンス。

lsofは引数で指定したファイルをopenしているプロセスを表示してくれるので、
たとえばlibcrypto.soを使ってるのを探したければ、こんな感じでok。

% lsof /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
COMMAND     PID USER  FD   TYPE DEVICE SIZE/OFF     NODE NAME
python     2958 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
python     2967 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
python     2979 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
indicator  2990 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ssh        3435 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ssh        3438 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ssh        3611 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ssh        3622 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ssh        3636 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
ruby       3748 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
x11vnc    22351 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
w3m       25870 eban mem    REG    8,2  1961344 43253810 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0

2015-01-30 (Fri)

xargsの罠

xargsの-L1と-n1って1行につき1個書いてあるときは特に違いはないと思っていたが、罠があった。

-L max-lines
       Use at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line to be
       logically continued on the next input line.  Implies -x.

つまり後ろに空白があると次の行へ継続しているとみなされる。

% printf "a \nb\n" | cat -A
a $
b$
% printf "a \nb\n" | xargs -L1 -t
/bin/echo a b 
a b
% printf "a \nb\n" | xargs -n1 -t
/bin/echo a 
a
/bin/echo b 
b

適当に引数リストを作ってたりすると理解不能なバグになりそう。


2015-01-31 (Sat)

xargsの罠 その2

xargsで並列実行させる-Pオプションはお手軽でいいが、これにも罠がある。
単に-P4とつけても意味がない。

% seq 10 | xargs -t -P4
/bin/echo 1 2 3 4 5 6 7 8 9 10 
1 2 3 4 5 6 7 8 9 10

一気に実行されてしまう。ここでは-n1が必要になる。

% seq 10 | xargs -t -P4 -n1
/bin/echo 1 
/bin/echo 2 
/bin/echo 3 
/bin/echo 4 
1
/bin/echo 5 
2
4
/bin/echo 6 
/bin/echo 7 
3
/bin/echo 8 
5
/bin/echo 9 
7
6
/bin/echo 10 
8
10
9

結果は同じ場合が多いので気づきにくい。


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