シェル芸勉強会福岡サテライトの開催が、昨年の冬以降途絶えておりました。時間が取れなかったり、前回は大雨の影響で中止したりでした。 株式会社レスコ様の会議室を貸していただき、久しぶりに開催出来ました。いつもながら会議室管理者の方、ありがとうございます。今回は述べ8人の参加者が集いました。そのうち新規の方が3人、2人は遠方からの参加でした。 勉強会主催者の上田さん、問題作成と解説ありがとうございました。
勉強会の情報
勉強会主催者の上田さんが公開されているリンク集をご覧ください。
午前の部
最初に話したイントロです。
午前中は鳥海さんによる文字コードの話を聴く予定でしたが、方針を変えて主に初参加者向けに補足説明をすることにしました。勉強会の趣旨や内容、よく使うコマンドやその使い方や調べ方について話をしました。catのオプション、sort、uniq、comm、paste、ls、findとxargsの合わせ技、bc、awkなども一通り説明。
その後以前実施した「初心者向けシェル芸勉強会」で解いた問題をやってみることにしました。
シェル芸初心者向け勉強会
シェル芸勉強会過去問第2回(問題と解答)
解いてもらって解説をしたのは下記の問題です。
問題2: 計算
以下のファイル中の数字を全部足し算してください。
$ cat Q2/num 1 2 3 4 5 6 7 8 9 10
文字列処理で数式を作ってbcへ突っ込むという解答を解説しました。awk NF
は最後に改行を入れるためのおまじないみたいなものです。
$ cat Q2/num | tr '\n' ' ' | tr ' ' + | sed 's/.$//' | awk NF | bc 55
昼食
前回に新規開拓した中華料理店へ行きました。何故か福岡県や福岡市の良さやアレな事が話題になったりしました。福岡県と福岡市の相性ってアレだよねとか(自粛)。
午後の部
いよいよ問題にトライの時間。今回は難しくもあるがくだらない?問題とのことです、、、??
要するに「シェル芸bot映え」するような出力を目指す問題でした。シェル芸botについては、Twitterを使ってる人はフォローして使ってみてください。作者の方が手動でフォロー返しされたら利用可能になるので、しばしお待ちを。
今回はいつも以上に福岡サテライトなりのペースで、というより私なりのペースでフォローや解説を重視しながら進行した。
Q1
FizzBuzzの出力をアニメーション化する問題。福岡ではとりあえずFizzBuzzの問題を解くことにしました。普通はループで剰余計算の結果でif文書きますが、sedで文字列処理を使った解答を紹介しました。GNU sedの0~3
の様な行指定がポイントです。最後のxargs
は縦に長くなるのを嫌ったためです。。
$ seq 30 | sed '0~3s/$/Fizz/;0~5s/$/Buzz/;' | sed 's/^[0-9][0-9]*\([^0-9][0-9]*\)/\1/' | xargs 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz
Q2
福岡サテライトでは下記の出力を出すことまでを目標にしました。
/\ / \ / \ / \
出題者上田さんの解答前半部を補足説明しました。GNU sedのラベルを使った繰り返し処理という初心者殺しな内容でしたが、とりあえず理解してもらえた、、でしょうか?。繰り返しのb
コマンドは無限にくり返します。
$ echo ' /\' | sed ':a p;s@ /@/ @;b a' /\ / \ / \ / \ / \ ..(無限君)...
繰り返しコマンドでb
の代わりにt
を使うと、直前のsコマンドが失敗するまで繰り返します。
$ echo ' /\' | sed ':a p;s@ /@/ @;t a' /\ / \ / \ / \ / \
Q3
問題簡略化のため、3桁の数字で各桁を足すと15になる数字の列挙をする事にしました。bashのブレース展開、sedで空白を入れる、awkで処理という流れです。
$ echo {0..9}{0..9}{0..9} | tr ' ' '\n' | sed 's/./& /g' | awk '$1+$2+$3==15' | tr -d ' ' | xargs 069 078 087 096 159 168 177 186 195 249 258 267 276 285 294 339 348 357 366 375 384 393 429 438 447 456 465 474 483 492 519 528 537 546 555 564 573 582 591 609 618 627 636 645 654 663 672 681 690 708 717 726 735 744 753 762 771 780 807 816 825 834 843 852 861 870 906 915 924 933 942 951 960
awkの-F ''
オプションで空文字を区切り文字に指定すると、$1
から順に1文字ずつ扱えて便利ですね。
$ echo {0..9}{0..9}{0..9} | tr ' ' '\n' | awk -F '' '$1+$2+$3==15' | xargs 069 078 087 096 159 168 177 186 195 249 258 267 276 285 294 339 348 357 366 375 384 393 429 438 447 456 465 474 483 492 519 528 537 546 555 564 573 582 591 609 618 627 636 645 654 663 672 681 690 708 717 726 735 744 753 762 771 780 807 816 825 834 843 852 861 870 906 915 924 933 942 951 960
Q4
bash4の機能でUnicodeのコードポイントを指定した文字表示が可能という解説をしました。macのログインシェルはbash3なので出来ません。Macの人はhomebrewで別途bash4をインストールしてもらいました。
$ echo -e \\U1F000 🀀
空文字の列とブレース展開して、同じ文字を繰り返し表示してみるところまでやってみました。
$ echo -e \\U1F00{0,1,2,3,6}{,,,} 🀀 🀀 🀀 🀀 🀁 🀁 🀁 🀁 🀂 🀂 🀂 🀂 🀃 🀃 🀃 🀃 🀆 🀆 🀆 🀆
Q5
出題者上田さんの解答例について前半部を解説しました。「山田」という漢字を下記の様にバナー化する出力を考えます。
__@__ __@__ __@__ @_@_@ @@@@@ _____ @@@@@ @_@_@ @@@@@ @_@_@ @@@@@
上記のバナーを1行ずつ確認すると、下記の3パターンになる事が分かります。
@@@@@ (5列とも埋まる) __@__ (3列目だけ埋まる) @_@_@ (1列目、3列目、5列目が埋まる) _____ (全て埋まらない)
上記の4パターンを1列に並べて、バナー化した「山田」が出るようにawkで順番に指定して出力します。1行目から3行めは3列目だけ埋まるパターン、4列目は1列目、3列目、5列目が埋まるパターンという具合です。
$ echo '@@@@@ __@__ @_@_@ _____' | awk '{print $2,$2,$2,$3,$1,$4,$1,$3,$1,$3,$1}' | xargs -n1 __@__ __@__ __@__ @_@_@ @@@@@ _____ @@@@@ @_@_@ @@@@@ @_@_@ @@@@@
Q6
時間がなかったため飛ばしました。
Q7
まずはfiglet
とtoilet
コマンドについて解説しました。インストール出来る人はインストールしてもらいました。次にmecabを使ってカタカナに変換しました。awkで-F , '{print $NF}'
と指定すると、カンマ区切りで最後の列のみを表示することを利用します。
$ echo とじ丼 | mecab -E '' | awk -F , '{print $NF}' トジ ドンブリ
あとは改行を外してtoiletコマンドへ入力します。
$ echo とじ丼 | mecab -E '' | awk -F , '{print $NF}' | tr -d '\n' | toilet m m m m # ""m # # # # # mm m mm#m" #mm mm #mm " # """" # # ""m " m" # ""m # # # m" # m" m" # "mm"" # "mm"" mm" m "m # # # # # # m"
出題者上田さんの解答では、漢字を平仮名にするのにkakasiを使っていらっしゃいました。こちらの方が簡単だったかも。そういえばkakasiを使った事があんまりなかったですね。
Q8
簡略化のため下記の様な出力をする事にしました。1行目を左右逆にして2行目に出力します。
鉄皿鶏のチリソース定食 食定スーソリチの鶏皿鉄
まずは左右逆にするrevコマンドを解説しました。
$ echo 鉄皿鶏のチリソース定食 | rev 食定スーソリチの鶏皿鉄
次にmoreutilsに含まれるpeeコマンドを解説しました。上記のrevコマンドを利用して下記の通りです。
$ echo 鉄皿鶏のチリソース定食 | pee cat rev 鉄皿鶏のチリソース定食 食定スーソリチの鶏皿鉄
peeコマンドの代わりに、teeコマンドとプロセス置換の組み合わせでも可能ですね。
$ echo 鉄皿鶏のチリソース定食 | tee >(cat) >(rev) > /dev/null 鉄皿鶏のチリソース定食 食定スーソリチの鶏皿鉄
終了後
福岡サテライトでは、シェル芸勉強会終了後、午前に引き続き初心者向けの話と「初心者向けシェル芸勉強会」でやったウォーミングアップ問題を解いていただいた。
色々と話をさせていただいたのだが、ここではコマンドライン自体もテキストデータだと思うと面白いよという話題について。数字の列挙から、日付を列挙するコマンド列をテキスト処理で作成します。
$ seq 0 2 | sed 's/^/date -d "/' | sed 's/$/ day"/' date -d "0 day" date -d "1 day" date -d "2 day"
作成したコマンド列をパイプでbashへ渡して実行します。繰り返し処理が無くてもコマンドを順次実行しますね。
$ seq 0 2 | sed 's/^/date -d "/' | sed 's/$/ day"/' | bash 2018年 9月 4日 火曜日 23:06:42 JST 2018年 9月 5日 水曜日 23:06:42 JST 2018年 9月 6日 木曜日 23:06:42 JST
最後に下記の解いてもらいました。
問題: 下記の日付一覧から、月毎の日の数を数えてください
$ cat date1 20150101 20150121 20150201 20150202 20150203 20150310
ポイントは年月までの左から6文字だけを切り出す事ですね。6文字を切り出すにはcut -c1-6
やawk {print substr($0,1,6)}
という意見が出ました。他にはgrepを使った下記も補足しておきました。
$ cat data1 | grep -o '^......' 201501 201501 201502 201502 201502 201503
後はuniq -c
を使って集計です。
$ cat data1 | grep -o '^......' | uniq -c 2 201501 3 201502 1 201503
更にsort -nr
までつなげて多い順に並べるのは、良く使うイデェオムということで補足しておきました。
$ cat data1 | grep -o '^......' | uniq -c | sort -nr 3 201502 2 201501 1 201503
全体を通して
今回は2名の方が遠方からいらっしゃいました。プログラミングの勉強をしていて、興味本位で参加してみたという方も。参加者の間口が少しでも広がるのは良い事だと思いました。
とりあえず福岡サテライトは私のアドリブでペース配分してみようと思います。後は参加者の反応をもっと見たり、時間をとる必要もありそうです。
終了後の後片付けで頼まれていた外の張り紙を外し忘れるミスをやってしまい、会場管理の方にご迷惑をおかけしてしまいました。次回からは張り紙外しを忘れないようにせねば。