参加しました!当日のYouTube Liveはこちら
Q1
日本語を入力せずに、「月月火水木金金」と出力する問題。元ネタ知らなくてジェネレーションギャップ。
$ echo 2021-12-0{6,6,7,8,9,10,10}| fmt -1 | xargs -I@ date --date @ +%a | paste -sd ''
月月火水木金金
固定の日付をdate
に渡して曜日だけを取り出し連結する感じですね。
Q2
echo 今楽日しのみ仕で事すはか、。
から初めて、今日の仕事は、楽しみですか。
に並び変える問題。そういえばこんなのあったな…
$ echo 今楽日しのみ仕で事すはか、。 | grep -o .. | awk '{a=a$1;b=b$2}END{print a,b}' FS= OFS=
今日の仕事は、楽しみですか。
並び変える前の文字列に注目すると、奇数番目を取り出したあと、偶数番目を順番に取り出せば、目的の文字列が得られることがわかりますね。というわけで、grep -o ..
で二列に分割したあと、awk
でa
,b
で成形して出力しました。
sel
を使うと以下のように書けます。ワォ!便利!
$ echo 今楽日しのみ仕で事すはか、。 | sel -D '' -d '' 1::2 2::2
Q3
ANSIエスケープで色がついた文字列から色を外す問題。わりとやりたくなることあるっすよねこれ。
$ cat */*56/red.txt | col | sed -E 's/(01\;31)?mK//g'
allergy's
bluejay
persevering
furtiveness's
remedied
hyaena's
summoner's
[Kin[m[Kjure[01;31m[Kpu[m[
injure
canons
polyphony
partridge
haste
slugs
wrangling
lulls
beta
fetus's
[01;31m[Kon[m[Ksaller[01;31m[
Visigoth's
purpose
xxd
をに渡してから、該当箇所を削っていくのかな?と思っていたんですが、Twitterでcol
というのがあるのを見つけたのでそれを試してみました。これを渡すと
aller01;31mKgymK's
bluej01;31mKaymK
per01;31mKsemKvering
furtiven01;31mKesmKs's
reme01;31mKdimKed
hyae01;31mKnamK's
sum01;31mKmomKner's
[Kin[m[Kjure[01;31m[Kpu[m[
01;31mKinmKjure
can01;31mKonmKs
01;31mKpomKlyphony
partr01;31mKidmKge
01;31mKhamKste
slu01;31mKgsmK
wra01;31mKngmKli01;31mKngmK
lu01;31mKllmKs
be01;31mKtamK
fetus01;31mK'smK
[01;31m[Kon[m[Ksaller[01;31m[
Vis01;31mKigmKoth's
01;31mKpumKrpose
こんな感じになります。あとは要らないところをsed
で削ればいいですね。red.ans.txt
に答えがあるのでdiff取ってみます
$ cat */*56/red.txt | col | sed -E 's/(01\;31)?mK//g' | diff - */*56/red.ans.txt
$ echo $?
0
大丈夫そうですね。man col
を読んでたら改行をいい感じにするツールみたいなことが書いてたんですけどわからん
Q4
端末に絵を描く問題。うむ。
$ R="\e[41m \e[49m" B="\e[44m \e[49m" C="\e[46m \e[49m" Y="\e[43m \e[49m" W=" ";echo -e "$R$R\n$W$R$R$W$W$B$B\n$W$W$W$W$W$B$Y$Y\n$C$C$C$C$W$B$Y$Y"
力業です。色を出す方法が分かれば地道に絵を描くだけですね。
Q5
ros_log
というファイルは複数プロセスが書き込みをするログファイルです。排他制御されてないとこうなるっすよね
小問1
VALUE
でgrep
すると見つかるかけたログの片割れを探してくださいという小問。めちょあむずそう
$ cat */*56/ros_log | awk '/INFO.*INFO|VALUE/{print $0}' | sed 's/\[INFO\]/\n[INFO]/g' | grep -vPe "DELTAS|SWEEPS|C" | awk 'NR==19{a=$0}NR==20{print a$0}4' | grep -Pe "INFO.*VALUE"
出力のフォーマットに注目すると、先頭に[INFO]
という文字列が存在することがわかります。ということは片割れがいる行にはINFO
が2回出てくることが考えられます。というわけで順番にこれを絞り込んでいきます。まずはログからINFO
が2回以上登場する行とVALUE
が登場する行をawk
で取り出します。次に[INFO]
が行頭にある方があとの成形に楽なので直前に改行を入れるsed
をはさみます。次はgrep
で余計な行を削除します。これは見つかったものを愚直に除外しただけですね。ここまでの出力をいったん下に書きます
$ cat */*56/ros_log | awk '/INFO.*INFO|VALUE/{print $0}' | sed 's/\[INFO\]/\n[INFO]/g' | grep -vPe "DELTAS|SWEEPS|C"| nl
1 [ INFO] [1634194596.339889867, 13.823000000]: VALUE ITERATION START
2 [ INFO] [1634194606.707089069, 24.183000000]: VALUE ITERATION END
3 [ INFO] [1634194644.06
4 [ INFO] [1634194646.869207875, 64.323000000]: VALUE ITERATION START
5 [ INFO] [1634194658.556429903, 76.002000000]: VALUE ITERATION END
6 [ INFO] [1634194673.985755427, 91.423000000]: VALUE ITERATION START
7 [ INFO] [1634194676.48
8 [ INFO] [1634194685.163231380, 102.592000000]: VALUE ITERATION END
9 [ INFO] [1634194708.5053
10 [ INFO] [1634194711.207208496, 128.623000000]: VALUE ITERATION START
11 [ INFO] [1634194721.287130748, 138.696000000]: VALUE ITERATION END
12 [ INFO] [1634194771.840389194, 189.223000000]: VALUE ITERATION START
13 [ INFO] [163
14 [ INFO] [1634194783.119124281, 200.494000000]: VALUE ITERATION END
15 [ INFO] [1634194836.175661508, 253.
16 [ INFO] [1634194838.176935414, 255.523000000]: VALUE ITERATION START
17 [ INFO] [163419484
18 [ INFO] [1634194849.754396571, 267.092000000]: VALUE ITERATION END
19 [ INFO] [1634194889.4049047
20 31, 306.723000000]: VALUE ITERATION START
21 [ INFO] [163419489
22 [ INFO] [1634194901.293168836, 318.602000000]: VALUE ITERATION END
23 [ INFO] [1634194926.527612289, 343.82
24 [ INFO] [1634194928.835154334, 346.130000000]: VALUE ITERATION START
25 [ INFO] [1634194931.730483322, 34
26 [ INFO] [1634194939.614970195, 356.902000000]: VALUE ITERATION END
27 [ INFO] [163419495
(説明のためにnl
で行番号を振っています)
20行目のやつが今回修復したい行ですね。そして19行目が片割れです。これを連結してやりましょう。行番号が分かっているのでもうawk
で直接連結します。あとはgrep
で欲しいところだけ取り出して終わりです。難しかった。
小問2
ログに含まれる二つの数字は時間とのこと。なので前後の数値を
$ ... | sel 3 4 | tr -d \[\]:, | awk 'BEGIN{a=0;b=0}{print $1-a,$2-b;a=$1;b=$2}'
差分を計算してるだけですね。果たして一致するか…。
1.63419e+09 13.823
10.3672 10.36
40.1621 40.14
11.6872 11.679
15.4293 15.421
11.1775 11.169
26.044 26.031
10.0799 10.073
50.5533 50.527
11.2787 11.271
55.0578 55.029
11.5775 11.569
51.5388 51.51
27.542 27.528
10.7798 10.772
んん…。
Q6
画像を縮小する問題。ただし4マスについて画素値が最小なものを選ぶようにすることという問題。なんか動画のエンコーディング規格を勉強しているときにこういうのやったな…
$ convert */*56/house.pgm -compress none pgm:- > o
$ cat o | awk 'NR==6,0' | awk '{for(i=1;i<=NF;i++)a[NR,i]=$i}END{for(i=1;i<=384;i+=2) {for(j=1;j<=384;j+=2) {x=a[i,j]<a[i+1,j]?a[i,j]:a[i+1,j];y=a[i,j+1]<a[i+1,j+1]?a[i,j+1]:a[i+1,j+1]; printf "%s ", x<y?x:y}; print "";}}' | cat <(echo -e "P2\n192 192\n255\n") - > result.pgm
力強いawkを書きました…。元の画像はpgmで、ヘッダー部分にP5
とあり、これは画素の部分はバイナリデータなことを表すので、加工しやすいようにconvert
で変換しておきます。あとは…まぁ…
解答例を見ていたら、データ列の左右でmin
を取ったあと、転置して同じことをすれば圧縮できるというのがあってマジで天才だなと思いました。人類は安泰ですね。
Q7
a^3+b^3=6963472309248
&& a<b
となるa
,b
の組を見つける問題。これは時間内に解答できませんでした。そしてなんかお試しで投げたコマンドが暴走してメモリ食いつぶしててちょっと笑ってしまいました(笑えない)
全探索するとめちゃめちゃ時間がかかってしまうので、範囲を狭めたりa^3
の判定をいい感じにしたりする必要があるらしいです。
というわけでこれを書きながら考えた解答が以下
$ seq 20000 | awk '6963472309248 - $1^3 > 0{print 6963472309248-$1^3}' | factor | nl -nln | sed -E 's/\s+/ /g' | awk '{delete(a);for(i=3;i<=NF;i++)a[$i]+=1;f=0;cum=1;for(x in a){f+=a[x]%3;cum*=x^(a[x]/3)};print $0,f==0?"ok":"ng",cum}' | grep ok | sel -- 1 -1 | awk '{if($1<$2){print}else{print $2,$1}}' | sort -ru
5436 18948
2421 19083
13322 16630
10200 18072
方針は解説でされたものと同じです。候補となるa^3
をリストアップしたあと、factor
にかけて素因数分解。その結果からa^3
となりうる行かどうかをawk
で計算しあとは成形して終わりですね。時間内にときたかったな…。
LT
今回もLTさせていただきました!
www.slideshare.net
ちょうど1年前のシェル芸勉強会でLTしたsel
というコマンドのリファクタリングを頑張ったよという話です。IO改善とか遅延評価とかなんかもうえらいこっちゃな話をしました。
github.com
今回パフォーマンスを意識したプログラミングをほぼ初めてやったので、良い勉強になりました。初期実装からかなり良くなったんですけど、self
のC言語版よりはまだ遅いらしいので恐ろしいですね(C言語版を持ってないのでわからんけど)
スライドにもあるとおりとりあえずモチベとしていたラインまでは達成したのでまぁ今のところはいいかなと思っています。気が向いた時にまた改善します。
終わり
今回も楽しかったです!図形を書いてくださいという問題、冷静に考えたら???????という感じなのですが、「そうだ、\e[42m
を使おう」と方針を決定できる自分が恐ろしかったです。慣れってやつかな…!
企画&開催ありがとうございました!