日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です。微力ながら共著させていただいた「シェル・ワンライナー160本ノック」をよろしくお願い申し上げます。

「第44回シェル芸勉強会:福岡サテライト」レポート

実に1年ぶり!シェル芸勉強会の福岡サテライトを開催いたしました。今回の会場は、福岡市エンジニアカフェのメインホールを使わせていただきました。参加者は全部で5人で、初参加者は3人でした。会場が想像以上に広くて立派で驚きました。福岡サテライトの規模的には、ちょっと立派過ぎて気が引けちゃう感もありました。

勉強会の情報

主催者上田さんが公開されているリンク集をご覧ください。

b.ueda.tech

会場

今回は福岡市の天神・赤煉瓦文化館内にある「エンジニアカフェ」のメインホールを始めて利用しました。 イベントの会場として利用するには、初回はコミュニティマネージャの方と対面で面談が必要です。 各施設・設備は無料で利用可能。メインホールではプロジェクターやインターネット接続が利用出来ます。プロジェクターはRGBやHDMI接続以外に、AirPlayがWi-Fi(AppleTV経由)で使えるのがすごく便利だったですね。

engineercafe.jp

twitter.com

twitter.com

twitter.com

スライド資料

どちらも話す時間が無かったのだが、ここに晒しておきます。

speakerdeck.com

speakerdeck.com

午前の部

午前中はぷるさんによるJavaScript入門でした。解説を聞きながら、nodeはNode.jsのREPL環境を試してみました。

JavaScripのObjectコピーは参照渡しなのよ。値渡しにするには{...Obj}みたいな書き方するらしいのよ。

$ node
> obj1 = {key:1}
{ key: 1 }
> obj2 = obj1
{ key: 1 }
> obj3 = {...obj1}
{ key: 1 }
> obj1.key = 2
2
> obj1
{ key: 2 }
> obj2
{ key: 2 }
> obj3
{ key: 1 }
> 

まあでもRubyのハッシュも参照渡しだったわね。pryはRubyのREPL環境。

$ pry
[1] pry(main)> hash1 = {:key=>1}
=> {:key=>1}
[2] pry(main)> hash2 = hash1
=> {:key=>1}
[3] pry(main)> hash1[:key] = 2
=> 2
[4] pry(main)> hash1
=> {:key=>2}
[5] pry(main)> hash2
=> {:key=>2}
[6] pry(main)> 

午後の部

今回の問題は、コマンドの組み合わせというよりawkでゴリゴリ頑張る系らしいです。

自分なりに考えた解答例を記載しました。今回は非常に頭を使う問題だったと思います。最初は「数独」を理解していなかったので、問題の意図が分からず置いてけぼりになりかけました。

Q1

第3フィールド以外はとりあえず無視して、行、列、値だけなら簡単な気がします。FS=は列(フィールド)の区切り文字を空文字に指定、要するに1文字ずつ区切るということでした。オプションで-F ''と指定しても同様です。

$ cat sudoku | awk '{for(i=1;i<=NF;i++){print NR-1,i-1,$i}}' FS=
0 0 5
0 1 3
0 2 *
0 3 *

次に第3フィールドを考えるのですが、この後がわかりませんでした。出題者上田さんの解答例では、3つずつ同じ物が続くということは、3で割って切り捨てれば良いという考え方でした。

Q2

ギブアップでした!

Q3

チョット要領が悪い解答を晒しておきます。

$ cat b | cut -c9- | tr -d ' ' | while read s; do [ -n "$s" ] && echo 123456789 | tr -d $s || echo; done | sed 's/./& /g' | paste -d ' ' a - | sed 's/ *$//'

ポイントはこちらです。例えば「1、3、5、6」以外の数字は何になるかはtrコマンドを使って処理しています。

$ echo 123456789 | tr -d 1356
24789

Q4

前半はデータを行列のマトリックスに戻す問題。ただし下記のような行は値が確定しています(入る数字の候補が1つに絞られている)。

...
4 4 4 * 5
...
6 5 7 * 7

値が確定している行は列数が5個になっているのを利用した解答がこちらです。パターンがNF==5NF!=5の2種類出現します。

$ cat c | awk 'NF==5{a[$1+1,$2+1]=$5}NF!=5{a[$1+1,$2+1]=$4}END{for(i=1;i<=9;i++){for(j=1;j<=9;j++){printf a[i,j]}print ""}}'
53**7****
6**195***
*98****6*
8***6***3
4**853**1
7***2***6
*6***7284
***419*35
****8**79

ナンバープレースの問題は解けませんでした。

Q5

積分は要するに細かい長方形の足し算という雑な解答がこちらです。もっと精度を上げるには、出題者上田さんの解答のように台形の足し算にしましょう。

$ seq 0 0.001 0.5 | awk '{printf "%.20f\n",log((cos($1)))*0.001}' | numsum
-0.0214458744608356

seqコマンドは引数を3つ指定すると、第二引数が増分になります。

$ seq 0 0.001 0.5
0.000
0.001
0.002
...
0.498
0.499
0.500

numsumコマンドは、数値のリストを足し算します。(Perl実装なので大量のデータは処理がやや遅いです)

$ seq 1 3 | numsum
6

Q6

色々とスマートな解答が出ていました。自分なりの解答がこちらです。

まずspeechファイルで空行の行番号を取り出し、speech2ファイルの行頭に順次付加します。

$ cat speech | awk 'length==0{printf "%02d\n",NR}' | paste -d' ' - speech2
03 んこも休み休み言え
04 春はあけぼの。夏は
07 ビも無ェ、うんこも
09 かた見だごとア無ェ
12 した。あなたのうん
13 こですお前それうん
14 こでも同じ事言えん

speechファイルには、行頭に行番号を付加します。

$ awk '{printf "%02d %s\n",NR,$0}' speech
01 このうんこを作った
02 のは誰だあっ!!う
03 
04 
05 夜。秋は夕暮れ。冬
06 はうんこハァ テレ
07 
08 無ェ、生まれてこの
09 
10 やつはとんでもない
11 ものを盗んでいきま
12 
13 
14 
15 の?疲れからか、

後はこの2つのデータをOUTER JOINします。行番号はゼロ埋めした固定長にしていますが、これはjoinコマンドで結合する際にキー列が辞書順に並んでいる必要があるためです。

$ cat speech | awk 'length==0{printf "%02d\n",NR}' | paste -d' ' - speech2 | join -a 2 - <(awk '{printf "%02d %s\n",NR,$0}' speech)
01 このうんこを作った
02 のは誰だあっ!!う
03 んこも休み休み言え 
04 春はあけぼの。夏は 
05 夜。秋は夕暮れ。冬
06 はうんこハァ テレ
07 ビも無ェ、うんこも 
08 無ェ、生まれてこの
09 かた見だごとア無ェ 
10 やつはとんでもない
11 ものを盗んでいきま
12 した。あなたのうん 
13 こですお前それうん 
14 こでも同じ事言えん 
15 の?疲れからか、

Q7

RSA暗号に関する問題でした。

小問1

巨大な整数の乗算と剰余計算出来るか?が壁。bcコマンドの力を利用した解答がこちらです。 まず計算する式の文字列を作成します。

$ cat message | tr ' ' '\n' | sed 's/$/^200%437/'
262^200%437
325^200%437
122^200%437
80^200%437
266^200%437
406^200%437
163^200%437
89^200%437
325^200%437
89^200%437
326^200%437

後はbcコマンドに食わせ、xargsで横に並べて完成です。

$ cat message | tr ' ' '\n' | sed 's/$/^200%437/' | bc | xargs
35 308 26 282 399 87 349 55 308 55 85

awkで計算するにはコツが必要で、GNUのMPFR、MPライブラリが必要です。

#数が大きすぎて桁が溢れてしまう
$ awk 'BEGIN{print 262^200%437}'
-nan

# -MオプションでGNUのMPFR、MPライブラリを有効にする。
$ awk -M 'BEGIN{print 262^200%437}'
35

GNUのMPFR、MPライブラリを利用するには、コンパイル時に組み込まれている必要があります。 --versionオプションで確認出来ます。

$ awk --version
GNU Awk 4.1.4, API: 1.1 (GNU MPFR 4.0.1, GNU MP 6.1.2)
...

小問2

ギブアップ!

小問3

ギブアップ!

終わりに

久しぶりに福岡サテライトを開催しましたが、今回は純粋に頭を使う問題が多くて初参加者へのフォローがあまり出来なかったように思います。出来る限りはサポート頑張ってみましたが、福岡サテライト参加者の皆様申し訳ありませんでした。問題の難易度が高くて参加者の方は大変だと思いますが、問題に食らいつくガッツは鍛えられるのではないかと思います。