文化の日っ!そんな日はシェル芸で頭脳をぶっ叩くのが良くないかい?世間一般は文化的祝日だが、そんな中福岡サテライト会場に3人が集まった。遠くは長崎から!福岡サテライト開催も19回目となった。
勉強会募集サイト
シェル芸界隈で合成文字が流行。 そのおかげでイベント通知ページのタイトルが見難い上に、ググられにくい??
本家東京会場募集
大阪サテライト会場募集
福岡サテライト会場募集
イベント報告関連
(上田会長による)jus共催 第37回シェル芸勉強会リンク集
(上田会長による)Togetterまとめ
午前の部
午前中は鳥海さんによる文字コードのお話を聴く。
twitter.comご静聴ありがとうございました。本日の午前の部で使用した資料です。
— Hidekazu Toriumi (@hid_tori) 2018年11月3日
次回、最終回予定です。https://t.co/JFCN8m1wso#シェル芸
EUCやShift-JISの成り立ちが面白かった。 Shift-JISのトリッキーなコードに闇を感じる。 ワンライナーで文字コード表やネストした三項演算子が繰り出される時間。 ダメ文字問題なんてあったのか!?
次回はようやくUnicodeの世界へ突入らしい。 しかし文字コードの設計って大変そうね・・・
vimに付属しているバイナリダンプやでコードが出来るxxdコマンドだが、 -uオプションで大文字出力が出来るのがあまり知られてないようだ。 xxdのオプションについては、マニュアルで一度確認してみよう。 読み出しのオフセットや長さ指定、出力の列数、エンディアンの切り替えなどの指定が出来る。
昼食
参加者みんなで会場近くのパレスチナ料理屋「D-TRANOI」という店へ入ってみた。
香辛料がすごく効いたサッパリした辛さ。 しかし食べるうちに口がヒリヒリしてきて、かなーり辛いが美味い。
戻ってからしばらくしてイントロを話す。バッチファイルやってみた的な。
午後の部
さていよいよ問題にトライの時間。数学の問題もあるらしいが・・・ 問題と解答例はこちら。(出題者の上田会長ブログ)
【問題と解答】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 仏説摩訶般若波羅蜜多心経 観自在菩薩行深般若波羅蜜多時。照見五蘊皆空。度一切苦厄。 舎利子。色不異空。空不異色。色即是空。空即是色。受想行識亦復如是。 (省略) 是無等等呪。能除一切苦。真実不虚故。説般若波羅蜜多呪。 即説呪曰。羯諦羯諦波羅羯諦波羅僧羯諦菩提薩婆訶。般若心経
会長の解答のようにawk
のsubstr()
関数を使うのが自然か。
別の考え方としてフィールド区切り文字を変更するやり方を考えてみる。
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までの整数を使った解答例がこちら。
乱数の発生はawk
のsrand()
関数と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つ目のawk
でfflush()
関数を使っている事。
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こういうやつか……
— くんすと (@kunst1080) 2018年11月3日
yes | head -10 | awk 'BEGIN{a=3.1;x=0.5}{x=a * x * (1-x); print x}'#シェル芸
こんな感じで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.combcなら100万ちゃんといくね
— eban (@eban) 2018年11月3日
echo 'x=0.5;a=3.9;for(i=1;i<=1000000;i++){x;x=a*x*(1-x)}' | bc -l | sort -u | wc -l
1000000#シェル芸
終了後
勉強会で出てきた事例に関連のあるブログ記事を書いてたのを思い出した。 休息の後、手前味噌ながら自作記事を紹介しながら内容の解説をした。
全体を通して
前回に続いて、今回も長崎から手練れのシェル芸人の方が遠路はるばる参加された。
参加者の方がレベルアップされてきたのも嬉しい。
grep
の-f
オプションについて解説したところ、次の問題で活用出来る!と教えていただけたり。
参加者の増減はあるが、地味ながらそれなりに効果は出てきたかな?と手応えを感じた回だった。