日々之迷歩

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

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

第29回シェル芸勉強会へ遠隔参加

梅雨なのにあんまり雨が降らずこれはアカンと思う今日この頃。通例では偶数月がシェル芸勉強会の月だが、今回は都合により7月1日での開催となった。今回も株式会社エスコ様(旧ベータソフト様)の会議室を利用させていただいた。

会場への移動中は暑かった!この暑い中会場へ移動される参加者の方はお疲れ様である。今回は5人の参加者が集った。初参加の方もいらっしゃった。

勉強会募集サイト

本家東京会場募集

usptomo.doorkeeper.jp

大阪サテライト会場募集

atnd.org

福岡サテライト会場募集

atnd.org

イベント報告関連

今回も大阪サテライトのLTも、キュアエンジニア乱入も相まってすごかったようで。東京も本場はTL!?

第29回シェル芸勉強会まとめ

第29回シェル芸勉強会まとめ – 上田ブログ

大阪サテライト会場開催レポート

www.kunst1080.net

Togetterまとめ

togetter.com

午前の部

「eval系超絶ワンライナー教祖」鳥海さんによるPerl入門だった。ちなみにPerl歴0年だとか。資料はGitHub.ioで公開されている。

Perl の正規表現(仮題)

ワンライナーを書くのに便利な機能があることに改めて気が付いた内容だった。

  • ダイヤモンド演算子
  • 豊富な特殊変数
  • -naeなどの起動オプション

そういえば豊富な特殊変数については、こんなことを思い出した。

use English宣言をするとこうなる。

$ perl -e '$"=":";@a=(1,2,3);print "@a"'
1:2:3

$ perl -e 'use English;$LIST_SEPARATOR=":";@a=(1,2,3);print "@a"'
1:2:3

昼食

お昼は定番となった餃子の王将。開発環境の統一性に関する政治力の考察!?などの話題が上がる。

午後の部

午後の部開始前にイントロの話をする。富士山ががが・・・・そしてlessコマンド終了時にショボーンとなる人たちの救済はまだまだ必要性を感じた次第。

speakerdeck.com

そしていよいよ午後の部開始。今回は地獄の三部構成らしい。と言っても前回よりは難易度は低めだったかも。問題と解答はこちら。

【問題と解答】第29回激しいシェル芸勉強会 – 上田ブログ

福岡サテライトで考えて解説した内容は下記の通り。

Q1

問題の意図としてはjoinコマンドを使うんだろうと思いつつ、awkの連想配列を使った解答例。1列目と2列目をセットでキーにしている。

$ cat kadai1 kadai2 | awk '{a[$1" "$2]+=$3}END{for(v in a)print v,a[v]}' | sort -k1,1n
004 今泉 22
001 山田 40
005 鳥海 88
002 出川 30
003 上田 15

もう一つTukubaiのsm2コマンドを使った例。

$ cat kadai1 kadai2 | sort -k1,1n | sm2 1 2 3 3

Q2

ようやくjoinコマンド発動。-aオプションを使った補完の出番。途中まで出来たけどここから?と思っていたがあとはawkでゴニョゴニョやればよかった。続きは 会長の解答通り。

$ cat attend6 | tr ',' '\n' | sort | sed 's/$/ 出/' | join -a 1 attend -
001 山田 出出欠出出 出
002 出川 出出欠欠欠
003 上田 出出出出出 出
004 今泉 出出出出出
005 鳥海 欠出欠出欠 出

このブログを書いている時に考えた解答例を。

$ cat attend6 | tr ',' '\n' | sort | sed 's/$/ 出/' | join -a 1 -o 1.1 1.2 1.3 2.2 -e 欠 attend - | sed 's/ \(.\)$/\1/'
001 山田 出出欠出出出
002 出川 出出欠欠欠欠
003 上田 出出出出出出
004 今泉 出出出出出欠
005 鳥海 欠出欠出欠出

MacやFreeBSDな方はこちら。-oオプションでの列指定がコンマ区切りになるのに注意。もしくはcoreutilsのgjoinコマンドを使うべし。

$ cat attend6 | tr ',' '\n' | sort | sed 's/$/ 出/' | join -a 1 -o 1.1,1.2,1.3,2.2 -e 欠 attend - | sed 's/ \(.\)$/\1/'
001 山田 出出欠出出出
002 出川 出出欠欠欠欠
003 上田 出出出出出出
004 今泉 出出出出出欠
005 鳥海 欠出欠出欠出

Q3

色々ゴニョゴニョやってみたがスッキリ行かず。

Q4.1

まずは各行の文字列長を1列目に付けてみる。

$ echo -1 4 5 2 42 421 44 311 -9 -11 | tr ' ' '\n' | sort -n | awk '{print length,$0}' 
3 -11
2 -9
2 -1
1 2
1 4
1 5
2 42
2 44
3 311
3 421

更に数値がマイナスの行の文字列長にマイナスを付ける。

$ echo -1 4 5 2 42 421 44 311 -9 -11 | tr ' ' '\n' | sort -n | awk '{print length,$0}' | sed '/-/s/^/-/' 
-3 -11
-2 -9
-2 -1
1 2
1 4
1 5
2 42
2 44
3 311
3 421

後は1列目をキーにして横並びの処理をすれば完成。

$ echo -1 4 5 2 42 421 44 311 -9 -11 | tr ' ' '\n' | sort -n | awk '{print length,$0}' | sed '/-/s/^/-/' | awk '{a[$1]=a[$1]" "$2}END{for(v in a)print v,a[v]}' | sort -k1,1n | awk '{$1="";print}'
-9 -1
2 4 5
42 44
311 421

Q4.2

こちらの問題までは追えず。会長の解答例以外に、sortコマンドの-gオプションを使えば+符号がついても数値による並べ替えが出来る知見を得た!

$ echo 4 +5 -1 -2 | tr ' ' '\n' | sort -n
-2
-1
+5
4

$ echo 4 +5 -1 -2 | tr ' ' '\n' | sort -g
-2
-1
4
+5

Q5

データの回転をするには天地返し+行列変換をすればいいのでtac | rs -Tの技が使えないか?MacやFreeBSDの場合はtacコマンドの代わりにgtactail -rを使う。

$ seq 1 9 | xargs -n 3
1 2 3
4 5 6
7 8 9

$ seq 1 9 | xargs -n 3 | rs -T | tac
3  6  9
2  5  8
1  4  7

相手のデータは三角なので四角にすればいいんじゃ?と四角にしている間にタイムアップ・・・

Q6

まずは問題のデータと全ての素数を混ぜ合わせて並べ換える。ここまでは上田会長の解答とほぼ同じ。

$ seq 1 100 | gfactor | awk 'NF==2{print $2}' | cat <(cat prime | tr ' ' '\n') - | sort -n
2
2
3
3
(出力は省略)
89
89
97
97

ここから重複の数を数える。

$ seq 1 100 | factor | awk 'NF==2{print $2}' | cat <(cat prime | tr ' ' '\n') - | sort | uniq -c | sort -s -k2,2n
      2 2
      2 3
(出力は省略)
      1 23
      1 29
(出力は省略)
      2 89
      2 97

後は1列目が1の時に改行して完成。

$ seq 1 100 | factor | awk 'NF==2{print $2}' | cat <(cat prime | tr ' ' '\n') - | sort | uniq -c | sort -s -k2,2n | awk '$1==2{printf $2" "}$1==1{print ""}' | awk NF
2 3 5 7 11 13 17 19 
31 37 41 43 47 53 59 
67 71 73 79 83 89 97 

Q7

まずはnkfコマンドに実体参照の復号化機能があることを解説。後は頑張ってタグを取れば良さそう。最後まで解答を作る時間が無かった。

$ echo 'a&#160;b' | nkf --numchar-input
a b

後はテキストブラウザのw3mを使う解説もあった。

$ w3m -dump nyaan.html 
                                                        
 "m   mmm                                     "m        
 m" "" m""        m m                         m"        
 #              mm#m"#"m     ""      ""      m#m        
 # m #            "m mm"                    m"  #   m   
 "#   """"         #                       m"   "mm"    
                                                        

Q8

考えているうちに以前にやっていた「バナー芸人衆」という遊びを思い出す。

papiro.hatenablog.jp

これをヒントに考えていると「行列変換して空白だけの行を削除」すればいいやん!と閃いた解答例がこちら。まずは空白を-に置換して行列変換する。

$ cat shellgei | tr ' ' '-' | sed 's/./& /g;s/ $//' | rs -T
-  -  -  -  -  -  -  -
-  -  -  -  -  -  -  -
-  -  m  -  -  "  -  -
-  "  m  -  -  m  -  -
-  "  -  "  -  m  -  -
-  m  -  -  -  "  -  -
-  -  -  -  -  "  -  -
-  -  -  -  m  -  -  -
-  -  -  -  "  -  -  -
-  -  -  m  -  -  -  -
(出力は省略)
-  -  -  "  -  -  -  -
-  -  -  "  -  -  -  -
-  -  m  m  #  #  -  -
-  -  "  -  -  -  -  -
-  #  -  -  -  -  -  -
-  -  -  -  -  -  -  -
-  -  -  -  -  -  -  -
-  -  -  -  -  -  -  -
-  -  -  -  -  -  -  -
-  -  -  -  -  -  -  -

次のgrep -v '^[- ]*$'で空白だけの行を削除する。(元の空白は-に変換)後は2つめのrs -Tで元に戻し、-を空白に戻して完成。

$ cat shellgei | tr ' ' '-' | sed 's/./& /g;s/ $//' | rs -T | grep -v '^[- ]*$' | rs -T | tr -d ' ' | tr '-' ' '
                          m               
 ""m             m "m      #    # #      #
mm                # #      #mmm"""     m" 
  "    m" mmm""   # #   # m"   #   mm""m  
     m"     #mm  m" # m" "    #        #  
"mm""    """"  "m"  #"      m"         #  
                                          
                                          

午後の部終了後

スライドまで準備する時間がなかったので、メモを元に話をした。

バナー芸人衆

Q8を解くのにヒントになったブログ記事についてちらっと解説。端末遊び面白いよ。

真・マイナンバーシェル芸

xargsの話題が出たので、-Pオプションで並列化が出来るという例をちらっと話した。

papiro.hatenablog.jp

X.509デジタル証明書の話題

先日自前で運用しているCAを使ってSSLサーバ証明書の発行をしていたのだが、うっかり手が滑ってしまった。あれ?不正な日付で期限が設定出来てしまうやんね??

それからGoogle Chromeが発行先のサーバ情報を見るのに、SubjectAltNameをチェックするというように仕様が変わっていた。エラーが出てブーブー文句言われてショボーンとなっていた。

では改めてX.509デジタル証明書のデータを見てみようではないか。例としてTwitterが使っているSSLサーバ証明書を使う。デジタル証明書のDER形式のバイナリデータを復元するワンライナーがこちら。

バイナリデータの可視化はodコマンドを使っているオプションで-t x1cと指定すると、1バイトずつ16進数とASCII文字で出力してくれるので便利だ。

$ openssl s_client -connect twitter.com:443 < /dev/null 2> /dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' | sed '1d;$d' | base64 --decode | od -t x1c | head
0000000    30  82  06  89  30  82  05  71  a0  03  02  01  02  02  10  6f
           0 202 006 211   0 202 005   q 240 003 002 001 002 002 020   o
0000020    d0  1d  01  74  61  47  18  6f  80  92  a0  39  f3  b3  a8  30
         320 035 001   t   a   G 030   o 200 222 240   9 363 263 250   0
0000040    0d  06  09  2a  86  48  86  f7  0d  01  01  0b  05  00  30  7e
          \r 006  \t   * 206   H 206 367  \r 001 001  \v 005  \0   0   ~
0000060    31  0b  30  09  06  03  55  04  06  13  02  55  53  31  1d  30
           1  \v   0  \t 006 003   U 004 006 023 002   U   S   1 035   0
0000100    1b  06  03  55  04  0a  13  14  53  79  6d  61  6e  74  65  63
         033 006 003   U 004  \n 023 024   S   y   m   a   n   t   e   c

X.509デジタル証明書は、ASN.1記法に基づいたデータ構造になっている。OpenSSLのasn1parseサブコマンドで可視化出来る。

$ openssl s_client -connect twitter.com:443 < /dev/null 2> /dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' | sed '1d;$d' | base64 --decode | openssl asn1parse -i -inform DER
    0:d=0  hl=4 l=1673 cons: SEQUENCE          
    4:d=1  hl=4 l=1393 cons:  SEQUENCE          
(出力は省略)
  174:d=2  hl=2 l=  30 cons:   SEQUENCE          
  176:d=3  hl=2 l=  13 prim:    UTCTIME           :150902000000Z
  191:d=3  hl=2 l=  13 prim:    UTCTIME           :170730235959Z
  206:d=2  hl=3 l= 137 cons:   SEQUENCE          
(出力は省略)
  326:d=4  hl=2 l=  18 cons:     SEQUENCE          
  328:d=5  hl=2 l=   3 prim:      OBJECT            :commonName
  333:d=5  hl=2 l=  11 prim:      UTF8STRING        :twitter.com
(出力は省略)
  650:d=5  hl=2 l=   3 prim:      OBJECT            :X509v3 Subject Alternative Name
  655:d=5  hl=2 l=  32 prim:      OCTET STRING      [HEX DUMP]:301E820B747769747465722E636F6D820F7777772E747769747465722E636F6D

UTCTIMEの2つ目が期限日だ。YYMMDDHHMMSS形式にZがついた文字列になっている。最後に付いたZがUTC時間の意味だ。文字列、つまり不正な日付も入れることが出来るようだ・・・

UTF8STRINGの部分がCommonName(CN)と呼ばれる部分で、サーバ証明書の場合はホスト名になる。しかし最近のGoogle Chromeは次のOBJECT :X509v3 Subject Alternative Nameの部分を見るようになったようだ。実際のデータは16進数のバイナリデータとなっている。ホスト名が2つ登録されているが見えるだろうか?

$ echo 301E820B747769747465722E636F6D820F7777772E747769747465722E636F6D | xxd -p -r | od -t x1c
0000000    30  1e  82  0b  74  77  69  74  74  65  72  2e  63  6f  6d  82
           0 036 202  \v   t   w   i   t   t   e   r   .   c   o   m 202
0000020    0f  77  77  77  2e  74  77  69  74  74  65  72  2e  63  6f  6d
         017   w   w   w   .   t   w   i   t   t   e   r   .   c   o   m
0000040

openssl x509でSubject Alternative Nameを可視化したのがこちら。2つのホスト名が登録されているのがわかる。

$ openssl s_client -connect twitter.com:443 < /dev/null 2> /dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' | sed '1d;$d' | base64 --decode | openssl x509 -inform DER -noout -text | grep -A1 'Subject Alternative Name'
            X509v3 Subject Alternative Name: 
                DNS:twitter.com, DNS:www.twitter.com

バイナリデータを閲覧するコマンドについて補足をしておいた。MacやFreeBSDのodコマンドはマルチバイト文字に対応しているので便利だ。

$ echo 'The シェル芸 Power' | od -t x1c
0000000    54  68  65  20  e3  82  b7  e3  82  a7  e3  83  ab  e8  8a  b8
           T   h   e      シ  **  **  ェ  **  **  ル  **  **  芸  **  **
0000020    20  50  6f  77  65  72  0a                                    
               P   o   w   e   r  \n                                    
0000027

$ echo -n '🍣食いねえ' | od -t x1c
0000000    f0  9f  8d  a3  e9  a3  9f  e3  81  84  e3  81  ad  e3  81  88
           🍣  **  **  **  食  **  **  い  **  **  ね  **  **  え  **  **
0000020

またvimに付属のxxdコマンドについても説明しておいた。-p-p -rオプションを使った16進数への符号化と復号化、-bオプションでビット列(2進数)への符号化など。

$ echo 'The シェル芸 Power' | xxd -p
54686520e382b7e382a7e383abe88ab820506f7765720a

$ echo 'The シェル芸 Power' | xxd -p | xxd -p -r
The シェル芸 Power

$ echo 'The シェル芸 Power' | xxd -b
00000000: 01010100 01101000 01100101 00100000 11100011 10000010  The ..
00000006: 10110111 11100011 10000010 10100111 11100011 10000011  ......
0000000c: 10101011 11101000 10001010 10111000 00100000 01010000  .... P
00000012: 01101111 01110111 01100101 01110010 00001010           ower.

その後雑談を兼ねたいろんなお話が出てきた。皆さんいろんな環境でいろんな苦労をされているなあ。

シェル芸勉強会の意義を考えていたのだが「データに着目する」視点を身に付くのではないか?プログラミングの勉強会ではプログラム自体に着目する気がするが、シェル芸はデータストリームな処理なので必然的にデータに着目するからだ。これを意義と言っていいものかはまだ自信がないのだが。

今回は初参加の方もいらっしゃったので、もう少し自己紹介などの時間を取ればよかったと反省。自分なりに解説やサポート、話題提供を頑張ったつもりだが、もう少し肩の力を抜いていいかもしれない。福岡サテライト会場、東京と大阪の会場の皆様方、お疲れ様!