梅雨なのにあんまり雨が降らずこれはアカンと思う今日この頃。通例では偶数月がシェル芸勉強会の月だが、今回は都合により7月1日での開催となった。今回も株式会社エスコ様(旧ベータソフト様)の会議室を利用させていただいた。
会場への移動中は暑かった!この暑い中会場へ移動される参加者の方はお疲れ様である。今回は5人の参加者が集った。初参加の方もいらっしゃった。
勉強会募集サイト
本家東京会場募集
大阪サテライト会場募集
福岡サテライト会場募集
イベント報告関連
今回も大阪サテライトのLTも、キュアエンジニア乱入も相まってすごかったようで。東京も本場はTL!?
第29回シェル芸勉強会まとめ
大阪サテライト会場開催レポート
Togetterまとめ
午前の部
「eval系超絶ワンライナー教祖」鳥海さんによるPerl入門だった。ちなみにPerl歴0年だとか。資料はGitHub.ioで公開されている。
ワンライナーを書くのに便利な機能があることに改めて気が付いた内容だった。
- ダイヤモンド演算子
- 豊富な特殊変数
-nae
などの起動オプション
そういえば豊富な特殊変数については、こんなことを思い出した。
#シェル芸 Perlの特殊変数はなかなか覚えられなかったので use English を使っていた覚えが。
— ぱぴろんちゃん👓 (@papiron) 2017年7月1日
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コマンド終了時にショボーンとなる人たちの救済はまだまだ必要性を感じた次第。
そしていよいよ午後の部開始。今回は地獄の三部構成らしい。と言っても前回よりは難易度は低めだったかも。問題と解答はこちら。
福岡サテライトで考えて解説した内容は下記の通り。
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
コマンドの代わりにgtac
かtail -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 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
考えているうちに以前にやっていた「バナー芸人衆」という遊びを思い出す。
これをヒントに考えていると「行列変換して空白だけの行を削除」すればいいやん!と閃いた解答例がこちら。まずは空白を-
に置換して行列変換する。
$ 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オプションで並列化が出来るという例をちらっと話した。
X.509デジタル証明書の話題
先日自前で運用しているCAを使ってSSLサーバ証明書の発行をしていたのだが、うっかり手が滑ってしまった。あれ?不正な日付で期限が設定出来てしまうやんね??
期限が6月31日だって!?
— ぱぴろんちゃん👓 (@papiron) 2017年6月27日
$ openssl x509 -noout -enddate -in cert.pem
notAfter=Jun 31 23:59:59 2018 GMT
それから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.
その後雑談を兼ねたいろんなお話が出てきた。皆さんいろんな環境でいろんな苦労をされているなあ。
シェル芸勉強会の意義を考えていたのだが「データに着目する」視点を身に付くのではないか?プログラミングの勉強会ではプログラム自体に着目する気がするが、シェル芸はデータストリームな処理なので必然的にデータに着目するからだ。これを意義と言っていいものかはまだ自信がないのだが。
今回は初参加の方もいらっしゃったので、もう少し自己紹介などの時間を取ればよかったと反省。自分なりに解説やサポート、話題提供を頑張ったつもりだが、もう少し肩の力を抜いていいかもしれない。福岡サテライト会場、東京と大阪の会場の皆様方、お疲れ様!