「第35回シェル芸勉強会 大阪サテライト」の復習
2018年4月7日に開催された「第35回シェル芸勉強会 大阪サテライト」に参加しました。
前回よりは花粉症の自覚症状がいくらかマシになりましたが、問題の難度が通常の酷さ+αになりましたので疲労度は今回の方が高かったです。
当日に解けなかった問題も多く、Q1から打ちのめされた回となりました(スラスラと解答している方々、凄いというか怖いです)。
シェル芸勉強会:
問題と解答例:
動画:
A1(宿題):
$ curl -m 10 parrot.live | less > parrot; perl -e 'open($FH,"<","parrot");while(<$FH>){if(/2J/){print($str);$str=$_;select undef,undef,undef,0.07}else{$str.=$_}}'
(...生け捕り開始...)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 20570 0 20570 0 0 11204 0 --:--:-- 0:00:01 --:--:-- 11203
(...生け捕り終了...)
.ccccccc.
.ccckNKOOOOkdcc.
.;;cc:ccccccc:,:c::,,.
.c;:;.,cccllxOOOxlllc,;ol.
.lkc,coxo:;oOOxooooooo;..:,
.cdc.,dOOOc..cOd,.',,;'....':l.
cNx'.lOOOOxlldOc..;lll;.....cO;
,do;,:dOOOOOOOOOl'':lll;..:d:''c,
co..lOOOOOOOOOOOl'':lll;.'lOd,.cd.
co.'dOOOOOOOOOOOo,.;llc,.,dOOc..dc
co..lOOOOOOOOOOOOc.';:,..cOOOl..oc
.,:;.'::lxOOOOOOOOOo:'...,:oOOOc.'dc
;Oc..cl'':lldOOOOOOOOdcclxOOOOx,.cd.
.:;';lxl''''':lldOOOOOOOOOOOOOOc..oc
,dl,.'cooc:::,....,::coooooooooooc'.c:
cNo.................................oc
Q1から難しく、解けないまま時間切れとなったため、宿題として解くことにしました。
前半のcurl
とless
を使った「生け捕り」の部分では、curl
に-m <秒数>
のオプションを付けて実行することで10秒間のみキャプチャを行った後、データ内のエスケープシーケンスが削除されないようにless
に渡してからファイルparrot
にリダイレクトしています。
後半は普通のPerlワンライナーです。ファイルparrot
には画面再描画用のエスケープシーケンスとして「ESC[2J」という文字列がありますのでそれを手がかりとして処理を行います。
「2J」が含まれた行が現れるまで変数$str
に行のデータを収めていき、「2J」が含まれた行に達する毎に変数$str
のデータを出力します。
なお、sleep()
関数では1秒未満の遅延に対応していないため、select()
関数を使って0.07秒間のウェイトをかけています。
A2(宿題):
$ nkf -Z herohero | sed 's/^[0-9]\+/& /' | awk '{chr[$1]=$2;row=$1}END{for(i=1;i<=row;i++)print chr[i]}'
へ
ろ
へ
ろ
まず、ファイルherohero
の中身は次のようになっています。
$ cat herohero
1へ
7ろ
9へ
13ろ
数字が全角になっていますので、nkf -Z
で半角にする必要があります。
これに、sed 's/^[0-9]\+/& /'
で数字の後に「 」を挿入した後、awk
に渡します。
第1フィールドの値(行番号)を添字に持つ配列chr
の各要素に第2フィールドの値を代入し、また変数row
に行番号を上書きで代入します。END
ブロックでfor
ループを1から変数row
の値(13)まで回し、配列chr
の値を出力していけば解答のようになります。
A3(改良):
$ awk '{data[$1][$2]+=1}END{for(i in data){printf("\n%d",i);for(j in data[i])printf(" %s:%d",j,data[i][j])}printf("\n")}' data
1 A:2 B:3
2 A:1 C:3
3 B:3 C:1 D:1
4 C:1
当日の解答には無駄な処理がありましたので改良したものを挙げておきます。
第1フィールドの値(1〜4)と第2フィールドの値(A〜D)をキーに持つ二次元の連想配列data
の各要素にそれぞれの出現回数を加算し、END
ブロック内でfor
の二重ループを使って題意に沿った書式で出力します。
A4:
$ w3m -dump 'https://namegen.jp/?sex=male&country=japan&lastname_cond=fukumu&lastname_rarity_cond=ika&firstname_cond=fukumu&firstname_rarity_cond=ika&middlename_cond=fukumu&middlename_rarity_cond=ika' | sed '29,89!d' | awk '!/^\[/{print $2}'
わたなべみのる
きたがわつばさ
おおかわまさひろ
ゆあさあきひろ
うらたひろゆき
おおたきしんいち
まつだいらりょう
こむらまさし
ひらこだいじろう
みすあきひろ
(...略...)
しせきてつあき
しまみやよしき
ごんないたかし
むろしまひさと
ざいかわながまさ
こがみひろあき
とみなかふみのり
みつしろくに
みねはらまさのり
うつやまふみひさ
「すごい名前生成器 - 創作・ゲームに使えるランダム人名ジェネレータ」のページをw3m
で取り込み、sed
とawk
で不要な部分を取り除いて表示すればOKです。
A5(宿題):
$ echo 響け!ユーフォニアム | awk '{len=length($1)/2;for(i=0;i<len;i++){L=substr($1,1,len-i);R=substr($1,len+1+i);str[i]=L""R}}END{for(i=0;i<=len;i++){SP="";for(j=0;j<i;j++){SP=SP" "}print SP""str[i]}for(i=len;i>=0;i--){SP="";for(j=i;j>0;j--){SP=SP" "}printf SP;system("echo "str[i]"|rev")}}'
響け!ユーフォニアム
響け!ユォニアム
響け!ニアム
響けアム
響ム
ム響
ムアけ響
ムアニ!け響
ムアニォユ!け響
ムアニォフーユ!け響
宿題として解いてみましたが、awk
コマンド1回で片付いた代わりに結構手間がかかる解答になりました。
文字列「響け!ユーフォニアム」を左右2つに分割し、それぞれについてfor
ループ内のsubstr()
で必要な文字のみ抽出した後、それらを結合した文字列を配列str
の各要素に代入します。
その後、END
ブロックで出力の上半分と下半分をそれぞれfor
ループで必要な分の「 」を先頭に挿入しながら出力します。
なお、下半分の出力についてはsystem("echo "str[i]"|rev")
とすることで左右を反転しています。
A6:
$ seq 100000 | factor | awk '$NF<=23{sub(/:$/,"",$1);print $1}' | awk 'NR<=1985'
1
2
3
4
5
6
7
8
9
10
(...略...)
19950
19965
19968
19992
20000
20007
20020
20064
20102
20111
今回のシェル芸勉強会で最も易しいと感じた問題です(難度の基準がおかしい)。
factor
による素因数分解の結果に対し、次のawk
で最終フィールド($NF
)の値が23以上の行を抽出すれば簡単(?)に解答を導き出すことができます。
A7-1(別解):
$ seq 25 | ruby -r 'prime' -nle 'BEGIN{STR="💩うんこもりもり💩";idx=0};Prime.prime?($_.to_i)?(puts STR[idx];idx+=1):(puts [*"ぁ".."ん"].sample)'
ぢ
💩
う
す
ん
の
こ
と
る
を
も
り
り
ゎ
う
ぁ
も
む
り
ぴ
せ
し
💩
ざ
よ
当日の解答では素数番目でない文字に対して全て同じ文字を使いましたが、少し凝ってそれぞれランダムな平仮名が入るようにしてみました。
RubyのPrimeライブラリにある素数判定用のprime?()
メソッドを使い、素数の行である場合は変数STR
から1文字ずつ、そうでない場合は「ぁ」〜「ん」からランダムに1文字を出力します。
A7-2(宿題):
$ cat Q7-1.txt | awk '{printf $1" ";system("echo "NR"|factor")}' | awk 'NF==3{printf $1}END{printf "\n"}'
💩うんこもりもり💩
当日に解答し忘れましたので宿題として解答しました。A7-1に比べれば易しいです。
最初のawk
で、読み込んでいる現在の行番号(NR
)に対しsystem()
関数によってfactor
を適用します。
次のawk
で、フィールド数(NF
)が3つ、すなわち行番号が素数の行のみ第1フィールドに格納された文字を出力します。
A8:
$ cat a | factor | grep -P ':( \d)(\1){3}$' | awk '{sub(/:$/,"",$1);print $1}' | xargs | awk '{print $1"*"$2"*"$3"*"$4"="$1*$2*$3*$4}'
16*81*625*2401=1944810000
問題文には
ある自然数の4乗になっている組み合わせを1個以上
とありますので、ある自然数の4乗になっている数を4つ以上ファイルa
から見つけ出すことが出来れば良いことになります。
$ cat a | factor | grep -P ':( \d)(\1){3}$'
16: 2 2 2 2
81: 3 3 3 3
625: 5 5 5 5
2401: 7 7 7 7
このように、ある自然数の4乗になっている数が4つありますので、これらの数を掛け算すればOKです。
ちなみに、掛け算の結果である1944810000を素因数分解すると次のようになります。
$ echo 1944810000 | factor
1944810000: 2 2 2 2 3 3 3 3 5 5 5 5 7 7 7 7
LT大会:
超・記号オンリー難読化シェル芸
- 発表者: たいちょー(@xztaityozx_001)さん
数字と記号だけのシェル芸という変態極まりない発表です。date
コマンドの例がまるでBrainf*ckのソースコードのようです。
Dockerを使ったクライアントハイパーバイザー
- 発表者: くんすと(@kunst1080)さん
「第33回シェル芸勉強会 大阪サテライト」における同名のLTの続編です。実装方法等の詳細については、同名のスライドにて知ることができます。
デスクトップ環境が動くだけでなく音声もちゃんと出るようになっているのが何気に凄いです。
less でプレゼン
- 発表者: 小原一哉(@KoharaKazuya)さん
スライド作成ツール「Marp」用のMarkdownファイルを、ターミナル上でスライドショー化してしまうという発表です。
自分もスライドの作成にMarpを使っていますが、分割したMarkdownファイルをless
で表示していく手法は思い付きもしませんでした。
Google AIY Voice Kit
- 発表者: nmrmsys(@nmrmsys)さん
スマートスピーカーAIY Voice Kitをハックして:(){ :|:& };:
が実行できる危険シェル芸アシスタントに仕立て上げるという発表です。
…OK Google! DSA (Dangerous Shell Arts)!
yesコマンドは速くなっている
- 発表者: MSR(@msr386)さん
シェル芸人お気に入りのコマンドの一つであるyes
について、高速化の歴史とその仕組みを解説しています。
grep
もそうですが、GNU版のコマンドの実行スピードは速いです。
参考リンク:
- jus共催 第35回またまためでたいシェル芸勉強会報告 | 上田ブログ
- jus共催 第35回またまためでたいシェル芸勉強会 - Togetter
- 第35回シェル芸勉強会に参加しました - たいちょーの雑記
Thanx:
- 大阪サテライト:
- 主催: くんすと(@kunst1080)さん、so(@3socha)さん
- 会場: フェンリル株式会社 大阪本社様
- メイン会場:
- 講師: 上田隆一(@ryuichiueda)さん