記事投稿日: 2023年4月23日(日)
最終更新日: 2024年3月30日(土)
2023年4月22日に開催された第64回シェル芸勉強会にオンラインで参加しました。 そのときの記録をメモとして記事にしておこうと思います。 あと、解けそうな問題はChatGPT(GPT-4)にも解いていただこうと思います。
メールの内容から必要な情報だけ抜き出します。
cat S*/*64/*.txt|sed 's/-/ /g'|sed 's/:/ /g'|sed 's/:>//g'|sed 's/Re //g'|sort -k9|awk '{c[NR]=$3;d[NR]=$4;g[NR]=$7;h[NR]=$8;i[NR]=$9}END{for(j=1;j<length(i);j++){if(i[j]==i[j-1]){printf("%s %s %s %d\n",i[j],g[j-1]"->"h[j-1],g[j]"->"h[j],(c[j]-c[j-1])*24+d[j]-d[j-1])}}}'
awkでごり押ししました。 まずsedでメール内容を整形して、時刻を比較したいメール同士が並ぶようにsortで並べ替えを行います。 それからawkでメール内容をすべて配列に入れて、時刻の差分を計算して必要な情報だけ出力しました。 ちなみに、私の回答は不完全なので分と秒を考慮できていません。 まだまだ勉強が足りていない気がしますね。 精進します。
正規分布に従う乱数を生成します。
echo | awk 'BEGIN{srand();a=0}{for(i=0;i<12;i++)a+=rand()}END{printf("%lf\n",a-6)}'
私は正規分布が分からないので0~1の乱数を12個足して6を引いた値を出力しました。 解説で紹介されていた「cat /dev/urandom」から乱数を生成する方法が勉強になりました。 これから乱数を生成するときは使ってみようと思います。 数値だけではなくアルファベットの文字列もランダムに生成できるとのこと。 便利ですね。ありがとうございます。
awk 'BEGIN {srand(); u1=rand(); u2=rand(); z0=sqrt(-2*log(u1))*cos(2*3.14159265359*u2); print z0}'
Box-Muller変換を使っているらしいです。
与えられた行列が対称行列か判定します。
cat S*/*64/mat | python3 -c 'import numpy as np;A=[input().split() for _ in range(5)];A=np.array(A);AT=A.T;r="YES" if np.array_equal(A,AT) else "NO";print(r)'
awkで行列を扱うのは地獄になりそうだったのでPythonのNumpyを使って解きました。 解説ではdatamashコマンドが紹介されていて勉強になりました。 まだまだ知らないコマンドがたくさんありますね。 便利なコマンドは少しずつ覚えておきたい所存です。 また、二次元配列の入力に関しては以下の記事を参考にさせていただきました。
参考 : 競技プログラミングをPython3で解くcat S*/*64/mat | awk '{for(j=1;j<=5;j++)m[NR,j]=$j}END{sym=1;for(i=1;i<=5;i++){for(j=1;j<=5;j++){if(m[i,j]!=m[j,i]){sym=0;break}}if(!sym)break}print sym?"Symmetric":"Not symmetric"}'
awkで解いていただきました。
k-means法をシェル芸で実装してみます。
cat S*/*64/nums.0 | sort -k2 | awk '{a[$2]+=$1;b[$2]+=1}END{for(i=0;i<length(a);i++)printf("%d %lf\n",i,a[i]/b[i])}' > mean.1
awkが便利すぎますね。 ファイルの中身をsortを使ってクラスターごとに並べ替えます。 それからawkでクラスターごとの合計を配列に入れて最後に平均をとっています。 一次元配列で済む問題ならawkで十分戦える気がします。 もっとawkを勉強していきたい気持ちです。 勉強になりました。
小問2はワンライナーではしんどくなったので解説を見てなるほどなぁ~と感心していました。 あとChatGPTにBashのワンライナーでk-means法の実装をお願いしたところ、 「PythonやRを使ってください」と怒られてしまいました。すみません。
オイラーのφ関数をBashのワンライナーで実装します。
n=8;echo $n | factor | sed 's/.*://g;s/ /\n/g' | uniq | awk -F, -v N=$n 'BEGIN{a=N}NR1>{a*=(1-1/$1)}END{printf("%lf\n",a)}'
オイラーのφ関数というものを初めて知りました。 awkにBash側の変数が渡せなくて困っていましたが、Fオプション付けたらなんとかなりました。 以下の記事を参考にさせていただきました。 ありがとうございます。 こんなに単純な関数なのに互いに素な自然数の個数が出てくるのは不思議ですね。 数学の神秘を体感しました。 勉強になりました。 楽しかったです。
参考 : awkの中でシェルで作成した変数を扱うn=8; phi_n=0; gcd () { [ $2 -eq 0 ] && echo $1 || gcd $2 $(($1 % $2)); }; for ((i=1; i<=n; i++)); do if [[ $(gcd $i $n) == 1 ]]; then ((phi_n++)); fi; done; echo $phi_n
gcd関数から実装していただけました。
「seq 100 |」から始めて、各行の数字に対して、互いに素な自然数を列挙します。
seq 100 | awk 'function gcd(a,b){while(b!=0){r=a%b;a=b;b=r}return a}{printf("%d : ",$1);for(i=1;i<=$1;i++){if(gcd(i,$1)== "1"){printf("%d ",i)}};printf("\n")}'
gcd関数(最大公約数を求める関数)はChatGPTに実装していただきました。 互いに素な自然数がまだあまり理解できていませんが、 とりあえず解けたので良しとしましょう。 それにしてもChatGPTは便利ですね。 ある程度の無理を言っても許してくれる懐の深さも備えています。 最大公約数が1なら互いに素であると言えるということだけは理解できました(おそらく)。 勉強になりました。ありがとうございます。
第64回シェル芸勉強会についてメモを書きました。 シェル芸の得手不得手が少し理解できた気がします。 また、今まで知らなかったコマンドにも出会えたので良かったです。 ChatGPTにもご協力いただいてとても勉強になりました。 次回も参加させていただきたいと思います。 一度くらいは現地参加もしてみたいですね。 ということで、誠にありがとうございました。 またよろしくお願いいたします。 次回も楽しみにしています。
各シリーズの記事を下記にまとめてあります。