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させていただきました!
ちょうど1年前のシェル芸勉強会でLTしたsel
というコマンドのリファクタリングを頑張ったよという話です。IO改善とか遅延評価とかなんかもうえらいこっちゃな話をしました。
今回パフォーマンスを意識したプログラミングをほぼ初めてやったので、良い勉強になりました。初期実装からかなり良くなったんですけど、self
のC言語版よりはまだ遅いらしいので恐ろしいですね(C言語版を持ってないのでわからんけど)
スライドにもあるとおりとりあえずモチベとしていたラインまでは達成したのでまぁ今のところはいいかなと思っています。気が向いた時にまた改善します。
終わり
今回も楽しかったです!図形を書いてくださいという問題、冷静に考えたら???????という感じなのですが、「そうだ、\e[42m
を使おう」と方針を決定できる自分が恐ろしかったです。慣れってやつかな…!
企画&開催ありがとうございました!