期間限定ではあるが忙しさがピークに達し自分を見失いかけていたため、福岡サテライト会場開催の決断と通知が遅くなってしまい申し訳ありませんでした。今回も株式会社エスコ様(旧ベータソフト様)の会議室を利用させていただきました。 問題出題と解説の上田さん、ありがとうございました。参加者の皆様もお疲れ様でした。
会場の担当をしていただいている方は当日業務だったのだが、会場の準備や後片付け、鍵の開け閉めをしていただきました。 いつもありがとうございます。今回は6人の参加者が集いました。
勉強会の情報
勉強会主催者の上田さんが公開されているページをご覧ください。 b.ueda.tech
午前の部
今泉さんによるシグナルの解説でした。福岡サテライトでは、私なりに噛み砕いてシグナルの話をさせていただきました。
- プロセスはOSがPIDで管理
- シグナルでプロセス制御
- プロセス終了
- 一時停止
- コアダンプ
- 強制終了
- パイプクローズ
- ユーザー定義シグナル
kill
コマンドで指定したPIDにシグナル通知- Ctrl-CやCtrl-Zなどのキー操作でシグナル通知
kill -l
でシグナル一覧- SIGHUPで設定ファイル再読み込みや再起動(sshdやApache HTTPd Serverなど)
seq 100000 | head
でSIGPIPEの事例- bashの
PIPESTATUS
休憩している時に、CSVデータを行列置換とかがやりたいけど何か方法は無いか?という話題が上がりました。
awk
などで頑張る方法もあるが、rs
コマンドの-T
オプションで行列入替えが出来る話をしました。
$ seq 10 | xargs -n 2 1 2 3 4 5 6 7 8 9 10 $ seq 10 | xargs -n 2 | rs -T 1 3 5 7 9 2 4 6 8 10
ちなみに同様な処理をするのに、Tukubaiのtateyoko
というコマンドがあります。
Tukubaiオンラインコマンドマニュアル: tateyoko(1)
質問された方に話を詳しく聞いてみたところ、RDBに入れてJOINしたりするためのCSVデータを行列置換したいということでした。 最近テキストファイルをキーで連結する処理をやった事例があり、TLで話してみようかと準備をしていたので、午前中ではあるが資料の話をすることにしました。
昼食
お昼は会場近くの餃子の王将でした。定番になりつつあります。 Software Designの2017年1月号を購入してシェル芸特集を読んでやってみたという方がいらっしゃいました。ありがたいですね。
午後の部
いよいよ実践で悶える時間が始まりました。
今回もsed
がメインのようですが、awk
の力も借りつつLaTeXの文章を弄くり回す地獄を味わう問題のようです。
福岡サテライトで考えて解説した内容は下記の通りです。今回は気分を変えてUbuntuで解いてみました。
Q1.1
出題者上田さんの解答とほぼ同じでした。
Q1.2
出題者上田さんの解答例を参考にさせていただいて解説しました。
まずはsed
とgrep
の-B
オプションで必要になりそうな行を抜き出します。
$ cat contents.tex | sed -n '/\\begin{figure}/,/\\end{figure}/p' | grep -B1 caption \includegraphics[width=0.5\linewidth]{./figs/coordinate.eps} \caption{世界座標系とロボットの姿勢} -- \includegraphics[width=0.5\linewidth]{./figs/observation.eps} \caption{計測値} -- \includegraphics[width=0.5\linewidth]{./figs/two_poses.eps} \caption{ランドマークの計測値から2点の相対姿勢を求める} -- \includegraphics[width=0.8\linewidth]{./figs/observation_noise.eps} \caption{ランドマークの計測値の不確かさを表す共分散行列}
次に{}
の前後を消し去ります。
$ cat contents.tex | sed -n '/\\begin{figure}/,/\\end{figure}/p' | grep -B1 caption | sed 's/^.*{//' | sed 's/}.*$//' ./figs/coordinate.eps 世界座標系とロボットの姿勢 -- ./figs/observation.eps 計測値 -- ./figs/two_poses.eps ランドマークの計測値から2点の相対姿勢を求める -- ./figs/observation_noise.eps ランドマークの計測値の不確かさを表す共分散行列
後は並べ替えして整理すれば完成です。
$ cat contents.tex | sed -n '/\\begin{figure}/,/\\end{figure}/p' | grep -B1 caption | sed 's/^.*{//' | sed 's/}.*$//' | xargs -n 3 | awk '{print $2,$1}' 世界座標系とロボットの姿勢 ./figs/coordinate.eps 計測値 ./figs/observation.eps ランドマークの計測値から2点の相対姿勢を求める ./figs/two_poses.eps ランドマークの計測値の不確かさを表す共分散行列 ./figs/observation_noise.eps
Q2
出題者上田さんの解答例を参考にさせていただきました。 内容が複雑で福岡サテライトでは追いつく余裕が無かったため、段落番号を付けて2章だけ抜き出す処理を理解することにしました。
$ cat contents.tex | awk '/\\section/{a+=1}{print a,$0}' | grep '^2' 2 \section{問題} 2 2 %対向二輪型(その場で回転できるロボット)で、 2 平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで ... 2 任意のロボットの軌跡$\V{x}_{0:T}$がどれだけ$Z_{0:T}$を説明するかを 2 評価関数として定式化し、この評価関数を用いた最適化問題として定義する。 2 この評価関数については、次章の実装の中で説明する。
Q3
詳しく追う余裕がなかったため、一旦一行にしてしまってからキーワードの前後に改行を入れると扱いやすくなる、 というやり方を解説するに留めておきました。
$ cat contents.tex | tr -d '\n' | sed 's/\\footnote{/\n&\n/g'
Q4
キーを元にして、awkでデータをファイル別に分割する事例ですね。 参加者の方々はやり方をご存知ではないようでしたので、下記の例を解説しました。
数値を10で割った余り毎にデータを分割する例です。
$ seq 100 | awk '{a=$1%10; print $1 > "file"a}' $ head -n 2 file* ==> file0 <== 10 20 ==> file1 <== 1 11 ... ==> file8 <== 8 18 ==> file9 <== 9 19
Apacheログファイルを接続元ホスト毎に分割する例です。
$ head -n 3 access_log 192.168.0.1 - - [01/Jul/1995:00:00:01 +0900] "GET /history/apollo/ HTTP/1.0" 200 6245 192.168.0.2 - - [01/Jul/1995:00:00:06 +0900] "GET /shuttle/countdown/ HTTP/1.0" 200 3985 192.168.0.3 - - [01/Jul/1995:00:00:09 +0900] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085 $ mkdir sources $ cat access_log | awk '{print $0 > "sources/"$1}' $ head -n 1 sources/* ==> sources/192.168.0.1 <== 192.168.0.1 - - [01/Jul/1995:00:00:01 +0900] "GET /history/apollo/ HTTP/1.0" 200 6245 ==> sources/192.168.0.2 <== 192.168.0.2 - - [01/Jul/1995:00:00:06 +0900] "GET /shuttle/countdown/ HTTP/1.0" 200 3985 ...
Q5
出題者上田さんの解説を参考にさせていただき、「わかち書き」が出来るmecabについて説明しました。
Q6
出題者上田さんの解説を参考にさせていただき、私の方からも解説しました。
Q7
余裕が無かったのでパスしました。
Q8
出題者上田さんの解説を参考にさせていただきましたが、思ったような出力にならない不完全解答になってしまいました。
$ cat contents.tex | grep 'section' | grep -v '^%' | sed 's/\\label{.*}$//' | sed 's/{/ /' | sed 's/}$/ /' | awk '/\\sec/{s+=1;ss=0}/\\subsection/{ss+=1;sss=0}/\\subsubsection/{sss+=1}{print s"."ss"."sss,$0}' 1.0. \section はじめに 2.0. \section 問題 2.1.0 \subsection ロボットの姿勢と座標系 2.2.0 \subsection 観測 2.2.1 \subsubsection ランドマークの識別 2.2.2 \subsubsection ランドマークの姿勢計測 2.2.3 \subsubsection 計測値の記録 2.2.4 \subsubsection 計測値の誤差 2.3.0 \subsection 完全SLAM問題 3.0.0 \section graph-based SLAMの実装例 3.1.0 \subsection グラフのエッジを作る 3.1.1 \subsubsection $\V{\mu}_{c,t,t'}, \V{e}_{c,t,t'}$の計算 3.1.2 \subsubsection $\Sigma_{c,t,t'}, \Omega_{c,t,t'}$の計算 3.2.0 \subsection 最適化問題を作る 3.2.1 \subsubsection マハラノビス距離 3.2.2 \subsubsection 最適化する式 3.3.0 \subsection $\V{e}_{c,t,t'}$の勾配を求める 3.4.0 \subsection 問題を解く
午後の部終了後
イントロとして準備しておいた資料の話をしました。
九九の答えが36種類
数学的な証明については、大阪サテライト担当の@kunst1080さんが頑張られているのでご覧ください。
九九の答えが36種類であることについて、Ruby芸でmapとreduceを使って確認してみました。 考え方は@ebanさんの下記のシェル芸とほぼ同じです。
% echo {1..9}\*{1..9}\;|bc|sort -n|uniq|wc -l
— eban (@eban) 2017年4月8日
36#シェル芸
Rubyのrepeated_combinationと、mapとreduceでやってみました。
$ irb irb(main):001:0> (1..9).to_a.repeated_combination(2).map{|a|a.reduce(:*)}.uniq.size => 36
そこはreduce(:*)と書けます
— eban (@eban) 2017年4月22日
そもそもreduce不要でした。まあ3個以上の掛け算だったらreduce使えばええですね。
irb(main):001:0> (1..9).to_a.repeated_combination(2).map{|a,b|a*b}.uniq.size => 36
いや、reduce不要ですね。map{|a,b|a*b}
— eban (@eban) 2017年4月22日
次に計算結果を素因数分解して、掛け算のパターンを数えてみます。シェル芸もRuby芸も考え方は同じです。
まずはシェル芸の場合です。1列目をTukubaiのdelf
コマンドを使っています。awkなどで消しても良いでしょう。
$ echo {1..9}\*{1..9}\; | bc | factor | delf 1 | sort | uniq 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 3 2 2 2 3 3 2 2 2 5 2 2 2 7 2 2 3 2 2 3 3 2 2 5 2 2 7 2 3 2 3 3 2 3 3 3 2 3 5 2 3 7 2 5 2 7 3 3 3 3 3 3 3 3 3 3 3 3 5 3 3 7 3 5 3 7 5 5 5 5 7 7 7 7 $ echo {1..9}\*{1..9}\; | bc | factor | delf 1 | sort | uniq | wc -l 36
次にRuby芸です。REPL環境のirbを利用しました。
$ irb -r 'prime' irb(main):001:0> (1..9).to_a.repeated_combination(2).map{|a,b|a*b}.map{|a|Prime.prime_division(a).map{|p,n|[p]*n}.flatten}.uniq => [[], [2], [3], [2, 2], [5], [2, 3], [7], [2, 2, 2], [3, 3], [2, 5], [2, 2, 3], [2, 7], [2, 2, 2, 2], [2, 3, 3], [3, 5], [3, 7], [2, 2, 2, 3], [3, 3, 3], [2, 2, 5], [2, 2, 7], [2, 2, 2, 2, 2], [2, 2, 3, 3], [5, 5], [2, 3, 5], [5, 7], [2, 2, 2, 5], [3, 3, 5], [2, 3, 7], [2, 2, 2, 2, 3], [2, 3, 3, 3], [7, 7], [2, 2, 2, 7], [3, 3, 7], [2, 2, 2, 2, 2, 2], [2, 2, 2, 3, 3], [3, 3, 3, 3]] irb(main):002:0> (1..9).to_a.repeated_combination(2).map{|a,b|a*b}.map{|a|Prime.prime_division(a).map{|p,n|[p]*n}.flatten}.uniq.size => 36
ASCIIコード問題
競プロな方のTwitter LTで、ASCIIコードの大小を確認する話題がありました。
@ebanさんからLANG=C
な条件だとsort
コマンドはASCIIコード順に並べ替えしてくれるというアドバイスをいただきました。
それからASCIIコード順に文字列を列挙する方法として、下記のような例を話しました。
AWKを使う例です。
$ seq 33 125 | awk '{printf "%d %c\n",$1,$1}' 33 ! 34 " 35 # ... 123 { 124 | 125 }
iprintを使う例です。(macOSやUbuntuならパッケージでインストール可)
$ seq 33 125 | xargs i 33 0x21 041 0b100001 '!' 34 0x22 042 0b100010 '"' 35 0x23 043 0b100011 '#' ... 123 0x7B 0173 0b1111011 '{' 124 0x7C 0174 0b1111100 '|' 125 0x7D 0175 0b1111101 '}'
man ascii
でasciiコードのマニュアルを見てみます。
ASCII(7) BSD Miscellaneous Information Manual ASCII(7) NAME ascii -- octal, hexadecimal and decimal ASCII character sets DESCRIPTION The octal set: 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del
実は先日の夜の飲み会でかなりの酔っぱっており、若干体調が不良だったのでした。 その飲み会の時に誘った方も参加していただきました。 UNIXはあまり触ったことがないということで、出来るだけサポートはさせていただいたつもりだがどうだったでしょうか?