たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

第56回シェル芸勉強会に参加しました

参加しました!当日の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 ..で二列に分割したあと、awka,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をに渡してから、該当箇所を削っていくのかな?と思っていたんですが、Twittercolというのがあるのを見つけたのでそれを試してみました。これを渡すと

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"

f:id:xztaityozx:20211102002536p:plain

力業です。色を出す方法が分かれば地道に絵を描くだけですね。

Q5

ros_logというファイルは複数プロセスが書き込みをするログファイルです。排他制御されてないとこうなるっすよね

小問1

VALUEgrepすると見つかるかけたログの片割れを探してくださいという小問。めちょあむずそう

$ 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

今回パフォーマンスを意識したプログラミングをほぼ初めてやったので、良い勉強になりました。初期実装からかなり良くなったんですけど、selfC言語版よりはまだ遅いらしいので恐ろしいですね(C言語版を持ってないのでわからんけど)

スライドにもあるとおりとりあえずモチベとしていたラインまでは達成したのでまぁ今のところはいいかなと思っています。気が向いた時にまた改善します。

終わり

今回も楽しかったです!図形を書いてくださいという問題、冷静に考えたら???????という感じなのですが、「そうだ、\e[42mを使おう」と方針を決定できる自分が恐ろしかったです。慣れってやつかな…!

企画&開催ありがとうございました!