日々之迷歩

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

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

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

もう12月に突入したことが信じられない今日この頃だが、朝の寒さにちょっと負けそうになりながらもシェル芸勉強会の福岡サテライトを開催させていただいた。会場は株式会社レスコ様の会議室。素敵な会場でいつもありがたい。今回は総勢5人の参加者が集った。

勉強会募集サイト

本家東京会場募集

usptomo.doorkeeper.jp

大阪サテライト会場募集

atnd.org

福岡サテライト会場募集

atnd.org

イベント報告関連

今回のTLなどはどうだったのかな?

(上田会長による)jus共催 第32回 シェル芸勉強会の報告

jus共催 第32回全くインスタ映えしないシェル芸勉強会 | 上田ブログ

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

togetter.com

午前の部

午前中は鳥海さんによる、変態としか思えない領域にも勇敢に立ち向かう激・Perl講習会。最初から撃沈するオープニングだったが、しばらくするとそれは前座であってまだ始まってすらいないことに気がつく・・・内容的には下記のような処理が序の口の中の序の口という感じで・・・

$ echo 1234567 | perl -pe 's/(?<=\d)(?=(\d{3})+$)/,/g'
1,234,567

$ echo 1234567 | perl -pe 's/(.)(?=(\d{3})+$)/$1,/g'
1,234,567

内容が激しすぎて読むのに「覚悟」が必要な鳥海さんによる資料をご覧あれ。バックトラックの処理が見え見えになる、Perlの正規表現デバッグモードとかの話も。

Perlワンライナー入門

昼食

いつも行く餃子の王将とは違う中華料理店に行ってみたら、なかなか美味しかった。違う店を探索してみるのもええんじゃないかしら?

午後の部

午後はいよいよシェル芸勉強会の問題。ちなみに今回の問題と解答がどんな感じだったかというと・・・

twitter.com

問題と解答例はこちら。(出題者の上田会長ブログ)

【問題と解答】jus共催 第32回全くインスタ映えしないシェル芸勉強会 | 上田ブログ

今回も福岡サテライトなりのペースで、フォローや解説を重視しながら進めていった。

Q1

抜けた数字を空行で飛ばして出力する問題。上田会長の解答例はawkの配列を使ったものだった。

福岡からは1から9までの数字の列と重複比較する解答例を出しておいた。下記のようにuniq -cで重複数をカウントしておく。

$ echo 14679 | grep -o . | cat - <(seq 1 9) | sort | uniq -c
      2 1
      1 2
      1 3
      2 4
      1 5
      2 6
      2 7
      1 8
      2 9

あとは重複数が1の場合は空行を、2の場合はそのまま出力で完成。

$ echo 14679 | grep -o . | cat - <(seq 1 9) | sort | uniq -c | awk '$1==1{print ""}$1==2{print $2}'
1


4

6
7

9

重複しているかどうか?で考えるということで、この問題はcommコマンド案件だなと思ってたら、やっぱり解答例が出ていた。commコマンドの解説もしておいた。

twitter.com twitter.com

Q2

Q1の発展系だが・・・ギブアップ。

ASCIIコード使った解答を考えていたら下記の解答例を発見。

twitter.com

下記の補足解説をしておいた。

awkのファイル名引数

ファイル名指定の代わりにvar=valueの指定が可能。

$ man gawk
  コマンドラインで指定されたファイル名が var=val という形式ならば、
  それは変数への代入であると解釈されます。
  変数 var は値 val に設定されます
  (これは、すべての BEGINブロックを実行したあとに行われます)。                                    
  コマンドライン での変数の代入は、AWK が入力をフィールドやレコードに
  分割するためのセパレータを実行時に変更するのに便利です。
  また、1つのデータファイルに対し数回処理を行う必要がある場合、
  状態をコントロールするのにも便利です。

ASCIIコードの扱い

# asciiコードの確認
$ man ascii

# 10進数でasciiコードが97の文字を出力。
$ awk 'BEGIN{printf "%c\n" 97}'
a

# 16進数でasciiコードが`0x61`の文字を出力
$ echo 61 | xxd -p -r
a

Q3

問題の意味を間違えていた・・・素数のポート番号を取り出すと勘違い。まあ会長の解答どおりか。

Q4

rsコマンドで行列ひっくり返したり、tacコマンドで上下反転させたり、色々考えたがギブアップ。会長の解答を見てもまだピンと来ず・・・

Q5

多分正規表現の問題だと思ったのだが、あえて文字コードを使った解答を考えた。

Macのodコマンドを使って文字コードの対応を確認してみる。ウムラウトは16進数c3で始まる2バイト長の文字のようだ。MacやFreeBSDなどのBSD系OSに付属するodコマンドは、マルチバイト文字の出力に対応しているので分かりやすい。

# Macのodコマンド
$ od -t cx1 umlaut.txt 
0000000    w   ä  **   s   c   h   s   t       w   a   s   h      山  **
           77  c3  a4  73  63  68  73  74  20  77  61  73  68  20  e5  b1
0000020   **  田  **  **   x       S   c   h   r   ö  **   d   i   n   g
           b1  e7  94  b0  78  20  53  63  68  72  c3  b6  64  69  6e  67
(以下省略)

ちなみにLinux付属のGNU製odコマンドは、下記のようにマルチバイト文字部分が表示出来ない。

# Linux(Ubuntu)のodコマンド
$ od -t cx1 umlaut.txt
0000000   w 303 244   s   c   h   s   t       w   a   s   h     345 261
         77  c3  a4  73  63  68  73  74  20  77  61  73  68  20  e5  b1
0000020 261 347 224 260   x       S   c   h   r 303 266   d   i   n   g
         b1  e7  94  b0  78  20  53  63  68  72  c3  b6  64  69  6e  67
(以下省略)

勉強会の時間では解答出来なかったので、後ほど考えた解答がこちら。出来ればループを使わず解きたかったが上手くいかず。実行速度の効率は遅いがとりあえず気にせず。

まずは1単語ずつxxdコマンドで16進数ダンプをとる。後の処理を考えて各単語の最後に改行0aを入れておく。

$ cat umlaut.txt | tr ' ' '\n' | xargs -I@ bash -c 'echo @ | xxd -p'
77c3a473636873740a
776173680a
e5b1b1e794b0780a
(以下省略)

grepでc3で始まる4文字(ウムラウト)の16進数がある行を選び、xxdコマンドで元の文字に戻す。改行付きで16進数にしていたので、各単語が改行で区切られて出力している。

$ cat umlaut.txt | tr ' ' '\n' | xargs -I@ bash -c 'echo @ | xxd -p' | grep c3.. | xxd -p -r
wäschst
Schrödinger
Ö
Übel
Ärztin

Q6

Twitterの画面内にツイート数が表示されているので、スクレイピングしてツイート数の変化を検知すれば良い。スクレイピング自体はcurlを使って下記のようになる。

$ curl --compressed -s https://twitter.com/papiron | grep -o 'title="[,0-9]*ツイート"' | sed 's/title="\(.*\)ツイート"/\1/' | tr -d ','
18690

自分のTwitterアカウントをcurlコマンドで5秒毎に監視する解答例がこちら。横着して最初の1回目はエラーが出るが気にしない・・・

$ while true; do n=$(curl --compressed -s https://twitter.com/papiron | grep -o 'title="[,0-9]*ツイート"' | sed 's/title="\(.*\)ツイート"/\1/' | tr -d ','); [ "$n" -ne "$pre" ] && echo んほぉ!; pre=$n; sleep 5; done

Mac付属のcurlコマンドだと圧縮された状態で出力されるので--compressedオプションで解凍している。

$ curl -s https://twitter.com/papiron | file -
/dev/stdin: zlib compressed data

$ curl --compressed -s https://twitter.com/papiron | file -
/dev/stdin: HTML document, UTF-8 Unicode text, with very long lines

Q7

sedコマンドで置換や、trコマンドで行列置換や考えたがギブアップ。

ebanさんがImageMagick画像処理を使って解答していた・・・ふえぇ。

twitter.com

Ubuntuで実行したら最後に整形が必要だったので、追記してみた。

# Ubuntuで実行。ImageMagickのバージョンは6.8.9-9。
$ cat image.txt |sed '1iP1 23 6' | convert - -morphology Convolve '3x3: 0 1 0 1 0 1 0 1 0' -negate -morphology Convolve '3x3: 0 1 0 1 0 1 0 1 0' -negate -compress none PBM: | sed '1,2d;s/ //g' | tr -d '\n' | fold -w 23
00000000000000001000000
00000000001111111100000
00001100011111111110000
00011110001111111111000
00001100000111111110000
00000000000000001000000

このImageMagickでの解答、Macで実行すると上手くいかず。ImageMagickのバージョンが新しいのが原因か?

# Macで実行。ImageMagickのバージョンは7.0.7-13。
$ cat image.txt |gsed '1iP1 23 6' | convert - -morphology Convolve '3x3: 0 1 0 1 0 1 0 1 0' -negate -morphology Convolve '3x3: 0 1 0 1 0 1 0 1 0' -negate -compress none PBM: | sed '1,2d;s/ //g'
00000000000000000000000
00000000000000010000000
00000000000111111100000
00001100000111111100000
00000000000000010100000
00000000000000000000000
# 出力結果が解答と違う

Q8

ギブアップ・・・Unicodeプロパティを使った正規表現で出来るようだ。

全体を通して

午前の部も午後の部も、難易度は高めだったか?福岡会場の場合はサポート重視でやっていく必要がまだまだ高いのが現状でもあるが、自分としてはアドリブを効かせてポイントを説明したりする訓練の場でもある。

また参加者の方が主体になれるようにするにはどうするか?という点も悩みではある。しかし続けていくことで何か見えてくるかもしれない。

先日はTwitter上で、福岡独自に開催されたら面白そうなのにという意見もいただいた。難易度を下げた内容でやって欲しい、という意味かもしれない。実はシェル芸勉強会コワイけど興味ある、という方々が福岡にはまだいらっしゃるのかもしれない。