日々之迷歩

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

ITが複雑で難しくなっていく様に翻弄される日々です

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

文化の日っ!そんな日はシェル芸で頭脳をぶっ叩くのが良くないかい?世間一般は文化的祝日だが、そんな中福岡サテライト会場に3人が集まった。遠くは長崎から!福岡サテライト開催も19回目となった。

勉強会募集サイト

シェル芸界隈で合成文字が流行。 そのおかげでイベント通知ページのタイトルが見難い上に、ググられにくい??

本家東京会場募集

usptomo.doorkeeper.jp

大阪サテライト会場募集

atnd.org

福岡サテライト会場募集

atnd.org

イベント報告関連

(上田会長による)jus共催 第37回シェル芸勉強会リンク集

jus共催 第38回シェル芸勉強会リンク集 | 上田ブログ

(上田会長による)Togetterまとめ

togetter.com

午前の部

午前中は鳥海さんによる文字コードのお話を聴く。

twitter.com

EUCやShift-JISの成り立ちが面白かった。 Shift-JISのトリッキーなコードに闇を感じる。 ワンライナーで文字コード表やネストした三項演算子が繰り出される時間。 ダメ文字問題なんてあったのか!?

次回はようやくUnicodeの世界へ突入らしい。 しかし文字コードの設計って大変そうね・・・

vimに付属しているバイナリダンプやでコードが出来るxxdコマンドだが、 -uオプションで大文字出力が出来るのがあまり知られてないようだ。 xxdのオプションについては、マニュアルで一度確認してみよう。 読み出しのオフセットや長さ指定、出力の列数、エンディアンの切り替えなどの指定が出来る。

昼食

参加者みんなで会場近くのパレスチナ料理屋「D-TRANOI」という店へ入ってみた。

tenjinsite.jp

香辛料がすごく効いたサッパリした辛さ。 しかし食べるうちに口がヒリヒリしてきて、かなーり辛いが美味い。

戻ってからしばらくしてイントロを話す。バッチファイルやってみた的な。

speakerdeck.com

午後の部

さていよいよ問題にトライの時間。数学の問題もあるらしいが・・・ 問題と解答例はこちら。(出題者の上田会長ブログ)

【問題と解答】jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会 | 上田ブログ

今回は福岡サテライトでも問題をじっくり解いていくことにした。 サポートや解説はいつもより控えめでも大丈夫だった気がする。 参加者もレベルアップしてきたようで何よりだ。

Q1

モヤモやを除去・・・要するに結合文字を分離しろと? 解答例は会長の例を参照してもらうとして、モヤモヤ文字がどうなっているかを確認してみる

マルチバイトに対応しているMacやFreeBSD付属のodコマンドで確認出来るぞ。 16進数のコードでd288やd289になっている部分がモヤモヤだ。

$ echo 'jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会' | od -t x1c
0000000    6a  75  73  e5  85  b1  e5  82  ac  20  e7  ac  ac  33  38  e5
           j   u   s  共  **  **  催  **  **      第  **  **   3   8  回
0000020    9b  9e  d2  88  d2  88  d2  89  d2  88  d2  88  d2  89  e3  82
          **  **    ҈  **    ҈  **    ҉  **    ҈  **    ҈  **    ҉  **  シ  **
0000040    b7  d2  88  d2  89  e3  82  a7  d2  88  d2  89  e3  83  ab  d2
          **    ҈  **    ҉  **  ェ  **  **    ҈  **    ҉  **  ル  **  **    ҈
0000060    88  d2  89  e8  8a  b8  d2  88  d2  89  e5  8b  89  d2  88  d2
          **    ҉  **  芸  **  **    ҈  **    ҉  **  勉  **  **    ҈  **    ҉
0000100    89  e5  bc  b7  d2  88  d2  89  e4  bc  9a  0a                
          **  強  **  **    ҈  **    ҉  **  会  **  **  \n                
0000114

Q2

ファイルの中に記載された文字だけを抽出する問題。 私の解答はuniq-dオプションで重複チェックを利用したもの。

$ echo 不摂生 | grep -o . | cat - <(cat 仏説摩訶般若波羅蜜多心経 | grep -o . | sort | uniq) | sort | uniq -d
生
不

会長の解答はgrep-fオプションを使っていた。 grep-fオプションについては改めて解説をして補足した。

Q3

スクレイピングで元号リストを取得する必要がある問題。w3mを使って楽をした。 参加者の中から「grep-fオプションを使うといいんじゃ?」という意見が。 おおなるほろ!ということで下記のようなスッキリとした解答が出せた。

# 何度もアクセスすると迷惑なのでファイルに保存
$ w3m -dump https://edo100.tokyo/edogengolst/ | sed -n /天文/,/明治/p | awk '{print $1}' > gengo

$ cat gengo | grep -f edo
元和
元禄
享保
安政

grep-fオプションを使わない場合は、会長の例のようにちと苦労が必要。 だがuniq-fオプションで重複チェックに使わない列の指定はよく忘れる。要チェックや。

Q4

bashのブレース展開の問題だった。解答例は会長のを参照で。 {A..Z} {A..Z}{A..Z} {A..Z}{A..Z}{A..Z}と3つのブレース展開を使えば良かった。

Q5

ガウス分布の乱数発生は「シェルプログラミング実用テクニック」、 ヒストグラムを描く問題は「シェルスクリプト高速開発入門」にあったのを思い出す。 どちらの書籍も上田会長著。解答例は上田会長の例を参照のこと。

上記著書によると、0から1の範囲の一様乱数を12個ずつ足して6引くと、標準偏差1のガウス分布に近いな乱数が出せるようだ。 関連する内容のブログを以前に書いていたので、手前味噌ながら載せておく。 papiro.hatenablog.jp

Q6

これは文字を一つずつズラしながら表示する処理が必要な問題。 まずファイルの中身から4文字を1文字ズラしながら出力する処理を考えてみる。

$ cat 仏説摩訶般若波羅蜜多心経
観自在菩薩行深般若波羅蜜多時。照見五蘊皆空。度一切苦厄。
舎利子。色不異空。空不異色。色即是空。空即是色。受想行識亦復如是。
(省略)
是無等等呪。能除一切苦。真実不虚故。説般若波羅蜜多呪。
即説呪曰。羯諦羯諦波羅羯諦波羅僧羯諦菩提薩婆訶。般若心経

会長の解答のようにawksubstr()関数を使うのが自然か。

別の考え方としてフィールド区切り文字を変更するやり方を考えてみる。 awkのフィールド区切り文字を空文字で指定すると、 第一フィールド($1)が一文字目、第二フィールド($2)が二文字目として扱える。 要するに1文字ずつフィールド分割して処理が可能。 フィールド区切り文字の指定方法には、下記の2通りがある。

# 1. awkの-Fオプションを使う。
$ cat 仏説摩訶般若波羅蜜多心経 | tr -d '\n' | awk -F '' '{for(i=1;i<=NF-3;i++)print $i$(i+1)$(i+2)$(i+3)}'
観自在菩
自在菩薩
在菩薩行
(省略)
訶。般若
。般若心
般若心経

# 2. 第二引数(つまり入力ファイル名)に var=val の形式を指定すると、変数への代入と解釈される。
awkのフィールド区切り文字は特殊変数FSで指定可能。
$ cat 仏説摩訶般若波羅蜜多心経 | tr -d '\n' | awk '{for(i=1;i<=NF-3;i++)print $i$(i+1)$(i+2)$(i+3)}' FS=

後は2つのファイルについて4文字ずつズラした出力を取り出し、 両方のファイルに含まれるものを選び出せば良い。 解答例は会長のものを参照。uniq-fオプションを活用しているのがポイント。

Q7

a2 + b2がab + 1で割り切れる正の整数の組合せa,bの生成。 1から1000までの整数を使った解答例がこちら。 乱数の発生はawksrand()関数とrand()関数を利用。

$ yes | awk 'BEGIN{srand()}{print int(1000*rand())+1,int(1000*rand())+1}'
122 849
338 152
654 454
366 786
(省略)

後はawkでa2+b2をab + 1で割った剰余がゼロの時のみ出力するパターンを使えば良い。

$ yes | awk 'BEGIN{srand()}{print int(1000*rand())+1,int(1000*rand())+1}' | awk '!(($1^2+$2^2)%($1*$2+1))'
27 240
30 8
27 3
1 1
3 27
6 216

更に(a2+b2)/(ab+1)の計算も出力して確認する。 ポイントは2つ目のawkfflush()関数を使っている事。 fflush()関数を使わない場合、バッファリングされてなかなか出力されない。

$ yes | awk 'BEGIN{srand()}{print int(1000*rand())+1,int(1000*rand())+1}' | awk '!(($1^2+$2^2)%($1*$2+1)){print;fflush()}' | awk '{print $1,$2,($1^2+$2^2)/($1*$2+1)}'
125 5 25
8 30 4
27 3 9
64 4 16
8 2 4
112 30 4

(a2+b2)/(ab+1)が正の整数の二乗になっていることの確認までやるには、 上田会長の解答例を参照のこと。

出力結果を更にパイプで他のコマンドに渡す際、出力の量が少ないとバッファリングでなかなか出力されない現象が起きるので注意しよう。下記のコマンドを使う際、バッファリングさせない時に使う関数やオプションをまとめておく。

  • awk: fflush()関数
  • grep: --line-buffered オプション
  • sed: -u, --unbuffered オプション

Q8

前のデータの結果から次を出力し続ける計算。詳しくは上田会長の解答例を参照。

この問題はawkの出力時に小数点以下の桁を減らさないのがポイントだった。 sprintf()関数を使う方法もあるが、awkには数値出力時のフォーマットを指定するOFMTという特殊変数がある。

例としてこれを参考にしてみた。

twitter.com

こんな感じで100万行出力し、重複した数値が無いかを確認する。

$ yes | awk 'BEGIN{OFMT="%.20f";a=3;x=0.5}{x=a * x * (1-x); print x}'
0.75000000000000000000
0.56250000000000000000
0.73828125000000000000
0.57966613769531250000
0.73095991951413452625
(省略)

# 出力桁数が少ないと重複してしまう
$ yes | awk 'BEGIN{OFMT="%.5f";a=3;x=0.5}{x=a * x * (1-x); print x}' | head -n 1000000 | sort | uniq -d
0.65862
0.65873
0.65880
0.65886
0.65891

# 桁数を増やすと重複しなかった
$ yes | awk 'BEGIN{OFMT="%.20f";a=3;x=0.5}{x=a * x * (1-x); print x}' | head -n 1000000 | sort | uniq -d

これ一体何に使うの?と思ったら、カオスの研究で重要らしい?? 連続で重複しない数値をたくさん出す

bcで計算する方法もあった。

twitter.com

終了後

勉強会で出てきた事例に関連のあるブログ記事を書いてたのを思い出した。 休息の後、手前味噌ながら自作記事を紹介しながら内容の解説をした。

papiro.hatenablog.jp

papiro.hatenablog.jp

全体を通して

前回に続いて、今回も長崎から手練れのシェル芸人の方が遠路はるばる参加された。 参加者の方がレベルアップされてきたのも嬉しい。 grep-fオプションについて解説したところ、次の問題で活用出来る!と教えていただけたり。 参加者の増減はあるが、地味ながらそれなりに効果は出てきたかな?と手応えを感じた回だった。