日々之迷歩

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

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

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

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

問題作成と解説の上田さん、ありがとうございます。参加者の皆様お疲れ様でした。

勉強会の情報

勉強会主催者の上田さんが公開されているリンク集をご覧ください。

b.ueda.tech

午前の部

午前中は鳥海さんによる、難しい領域にも勇敢に立ち向かう激・Perl講習会でした。最初から撃沈するオープニングでしたが、しばらくするとそれすらも前座であってまだ始まってすらいないことに気がつきます。内容的には下記のような処理が序の口という感じです。バックトラックの処理が見え見えになる、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

昼食

いつも行く餃子の王将とは違う中華料理店に行ってみたら、なかなか美味しかったですね。違う店を探索してみるのもええ気がします。

午後の部

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

Q1

抜けた数字を空行で飛ばして出力する問題。

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

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

macOS付属のodコマンドを使って文字コードの対応を確認してみます。ウムラウトは16進数c3で始まる2バイト長の文字ですね。 macOSや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
(以下省略)

ちなみにGNU coreutils付属の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

macOS付属の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上で、福岡独自に開催されたら面白そうなのにという意見もいただきました。難易度を下げた内容でやって欲しい、という意味かもしれません。実はシェル芸勉強会コワイけど興味ある、という方々が福岡にはいらっしゃるかもしれません。