Just another Ruby porter,

〜2016年5月上旬〜


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

2016-05-01 (Sun)

第22回シェル芸勉強会 Q2 #シェル芸

というわけで2問目。

_ Q2 カレーライス 醤油ラーメン:

パイプより右側はマルチバイト文字を使わないという条件があるので注意。
どこをいじるかは決め打ちでいいので難しくはない。
等幅フォント前提と考えれば「醤油ラ」の3文字の2倍で6個の空白分だけインデントさせればいい。

% echo カレーライス 醤油ラーメン | (read a b; grep -o . <<<$a | sed "s/^/      /;3c$b")  
      カ
      レ
醤油ラーメン
      ラ
      イ
      ス

キモはread a bで一旦変数に入れてしまうと扱いやすい。

% echo カレーライス 醤油ラーメン | (read a b; grep -o . <<<$a | sed "3\!s/^/      /;3s/./$b/")

とかやると3\!sの扱いがbashで面倒なことになるのでやめた。
そのおかげで3cを思い付いたのでよしとしよう。


2016-05-02 (Mon)

第22回シェル芸勉強会 Q3 #シェル芸

3問目。

_ Q3 データの集計と復元:

Q3.ansにはなぜ空白が2つあってソートされてないのかという点を考慮するとこうなる。

% cat Q3 | awk '{a[$0]=a[$0]" "NR}END{for(i in a)print i, a[i]}' 
bababa  2 5
aaabbb  1 3 4
bbbbba  6

まったくもって模範解答と同じである。復元もやってることは同じ。

% cat Q3.ans | awk '{for(i=2;i<=NF;i++)a[$i]=$1}END{for(i=1;i<=length(a);i++)print a[i]}'
aaabbb
bababa
aaabbb
aaabbb
bababa
bbbbba

ソートする代わりに配列を使っているだけ。


2016-05-03 (Tue)

第22回シェル芸勉強会 Q4 #シェル芸

4問目。

_ Q4 素数行目に存在するりんごとみかんの数:

素数といえばfactorなので。

% factor {1..8} | paste - Q4 | awk 'NF==3{a[$NF]++}END{for(i in a)print i, a[i]}'
みかん 1
りんご 3

後半は全部awkで解いてるが基本的にはこれも模範解答と同じ。

例のprimesを使うならこんな感じ。

% primes 2 8 | sed 's/$/p/' | sed -nf- Q4 | sort | uniq -c
      1 みかん
      3 りんご

sedでsedスクリプトを生成し、

% primes 2 8 | sed 's/$/p/'
2p
3p
5p
7p

Q4から抜き出す。

% primes 2 8 | sed 's/$/p/' | sed -nf- Q4
りんご
みかん
りんご
りんご

あとは模範解答通り。


2016-05-04 (Wed)

第22回シェル芸勉強会 Q5 #シェル芸

5問目。会長が15分じゃ解けないと言ってました。

_ 足して10になる並びを全て見つけてみましょう(1 3 4 4 2 3 5 6 7 9 1 4):

素直に書くと3重ループになるのでかなり面倒。
面倒なのでRubyで解いてみたが、表示がだめだめすぎる。

% cat Q5 | ruby -ane '2.upto($F.size){|i|p $F.each_cons(i).map{|a|a.map(&:to_i)}.select{|x|x.inject(:+)==10}}'
[[9, 1]]
[[4, 4, 2], [2, 3, 5]]
[]
[]
[]
[]
[]
[]
[]
[]
[]

とりあえずちょっと見た目を整えておこう。

% cat Q5 | ruby -ane '2.upto($F.size){|i|$F.each_cons(i).map{|a|a.map(&:to_i)}.select{|x|x.reduce(:+)==10}.map{|x|p x}}'
[9, 1]
[4, 4, 2]
[2, 3, 5]
% cat Q5 | ruby -ane '2.upto($F.size){|i|$F.each_cons(i).select{|x|x.reduce(0){|r,e|r+e.to_i}==10}.map{|x|puts x*" "}}'
9 1
4 4 2
2 3 5

awkで考えてみたが、やはり模範解答とあまり変わらない。

% cat Q5 | awk '{for(i=1;i<=NF;i++){for(j=1;j<=NF-i;j++){a=s=$i;for(k=i+1;k<=j+i;k++){a=a" "$k;s+=$k};if(s==10)print a}}}'
4 4 2
2 3 5
9 1

2016-05-05 (Thu)

第22回シェル芸勉強会 Q6 #シェル芸

6問目。

_ X,Y,Zを置き換える:

これもsedスクリプトを生成させるわけだが、awkでやってみた。

% sed "$(awk '{print "s/"$1"/"$2"/g"}' Q6_2)" Q6_1
所謂いわゆる「死相」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
人間のからだに駄馬の首でもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

もちろん-f-でもいい。

% awk '{print "s/"$1"/"$2"/g"}' Q6_2 | sed -f- Q6_1
% sed 's| |/|;s|.*|s/&/g|' Q6_2 | sed -f- Q6_1

2016-05-06 (Fri)

第22回シェル芸勉強会 Q7, Q8 #シェル芸

今日は7問目と8問目の2問。

_ shutdown, reboot, exit, logout等以外で端末を閉じる:

特にひねりもないので。

% kill -9 $$

SIGTERMでは死ないのでSIGKILLで。

_ C++のコードに関数プロトタイプを:

関数を定義してるところから宣言を生成し、所定の場所に挿入する。

% cat Q8.cc | sed '/void/!d;s/$/;/' | sed '/name/r/dev/stdin' Q8.cc | tee >(g++ -xc++ -)
#include <iostream>
#include <string>
using namespace std;
void aho(void);
string nazo(void);

void aho(void)
{
	cout << nazo() << endl;
}

string nazo(void)
{
	return "謎";
}

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}
% ./a.out
謎

voidとかnameとかたまたまこの問題で使えるだけで本当ならちゃんとした正規表現でやるべき。

これもsedスクリプトを生成する方法が使える。

% cat Q8.cc | awk '/void/{print "/name/a" $0 ";"}' | sed -f- Q8.cc
% cat Q8.cc | sed '/void/!d;s|.*|/name/a&;|' | sed -f- Q8.cc

真ん中のawkとsedのやってることは同じ。

次にawkで挿入。
awkだけで標準入力を読み込ませるには-で可能。
getlineで最初に全部読み込んでしまえばいいわけだ。

% cat Q8.cc | sed '/void/!d;s/$/;/' | awk 'BEGIN{while(getline < "-")p=p"\n"$0};1;/using/{print p}' Q8.cc

ちょっとまどろっこしいと感じるならこんな手も。
awkではファイル名を指定するところでQ8=1のように変数を初期化できる。
このQ8という変数は指定した順番通り-(標準入力)が読み終わった後で評価される。
つまりフラグとして使える。

% cat Q8.cc | sed '/void/!d;s/$/;/' | awk '!Q8{p=p"\n"$0;next};1;/name/{print p}' - Q8=1 Q8.cc

!Q8はFILENAME=="-"でいいわけだが、こんな方法もあるということで。


2016-05-07 (Sat)

killされたプロセスの終了ステータス #シェル芸

シェル芸勉強のLTでtrueの終了ステータスが137になった話。
なぜ137かというとこれはシェルがやってる。
Bourne shell系は137になるが、これは128+9を意味する。
9はSIGKILLだ。つまりkillされると128+そのsignalの番号となる。

% (sleep 5; echo $?) & killall -9 sleep        
[1] 20526
137
% (sleep 5; echo $?) & killall -2 sleep
[1] 21126
130

内部コマンドのkillは-lで名前を教えてくれる。

% bash -c 'kill -l 2 9 130 137'           
INT
KILL
INT
KILL
% zsh -c 'kill -l 2 9 130 137'
INT
KILL
INT
KILL

だからこうするとわかりやすい。

% (sleep 5; kill -l $?) & killall -1 sleep
[1] 23383
HUP

128+SIGじゃないシェルも存在するらしい。


2016-05-08 (Sun)

Parallelで並列処理 #シェル芸

xargsだとquote文字のエスケープが面倒なことになるので、
そういうときはGNU Parallelがお勧め。

% seq -w 0 99999999999 | parallel --pipe -q mawk '{c=($1*6+$2*5+$3*4+$4*3+$5*2+$6*7+$7*6+$8*5+$9*4+$10*3+$11*2)%11;d=c<=1?0:(11-c);print $0 d}' FS=

--pipeで各々標準入力に入れてくれるし、適当に入力も分割してくれる。
さらにデフォルトで現在のコア数をチェックしてその数で並列処理されるし、
-qをつけると面倒なquote処理までやってくれる。至れり尽くせりだ。


2016-05-09 (Mon)

Windows10でEdyViewerを使う

楽天のEdyViewerはブラウザで動くわけだけど、
EdgeではだめなようでWindows10でもIEを使う必要がある。
Windows10にそんなもんあるのかというと、
ちゃんとWindowsアクセサリに存在する。
でIE11でアクセスすればあっさり使えてしまうのであった。


2016-05-10 (Tue)

10000ページのPDFを分割

縦書きPDFでも公開してるWeb小説があるんだけど、
なぜか1つのPDFになってるもんだから10000ページを超えている。
Sony Readerに入れてみて3000ページぐらいまでジャンプしてからページ送りしてみたら、
遅くて使い物にならない。というわけで適当に分割する。

とりあえず400ページで分割する。
pdftkだと

% pdftk foo.pdf cat   1-400 output foo-1.pdf
% pdftk foo.pdf cat 401-800 output foo-2.pdf

という感じで実行できればいいので

% for i in {0..10000..400};do pdftk foo.pdf cat $[i+1]-$[i+400] output foo-$(printf %03d $[i/400+1]).pdf

としてみた。章とか無視してしまうがまあ気にしない。


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