バレンタインデーを明日に控え、皆様いかがお過ごしだろうか?そんな中あいにくの雨天にも関わらず、参加いただきありがたや。素晴らしい会場のご提供にも感謝。そして恒例になりつつあるが、また写真撮るの忘れた・・・
会場の案内など
第21回シェル芸勉強会の福岡サテライト会場を開設させていただいた。イベント案内はこちら。福岡サテライトも今回で5回目の開催になった。
福岡サテライト会場案内
大阪サテライト会場の案内
5f01b3bc1d81c1fae2378cdc89.doorkeeper.jp
ちなみに大阪は今回も寺シェル芸で徳をつまれたようだ。
大阪サテライト会場です!
— くんすと (@kunst1080) February 13, 2016
※入り口は裏手ですのでお間違えなきよう #シエル芸 pic.twitter.com/lAuOSNAJnr
— くんすと (@kunst1080) February 13, 2016
東京本家勉強会の案内
Togetterまとめ
勉強会当日のTwitterまとめはこちら。ハッシュタグは#シェル芸。
勉強会レポート
午前の部について
・・・前置きが長くなってしまった。午前中の部は自宅から遠隔参加した。午前の部は正規表現の濃いお話と、シェルがコマンドを実行するまでに何が起きているか?という内容だった。どちらもかなり興味深い内容だった。
正規表現の濃いお話
www.slideshare.net
勉強会本番
さて、ようやく午後からの勉強会本番。今回は新しく学生さんがいらっしゃったり、また遠くは大分県日田から来られた方もいらっしゃったりで、ありがたや。また、IT専門家というよりユーザ企業さんの情報部門な方もいらっしゃった。いい傾向だ。参加者は全員で8人だった。
まずはやっつけなイントロスライドのお話を少々。その後勉強会のライブストリームに突入した。
やっつけイントロスライド
www.slideshare.net
さて今回の問題は「シェルプログラミング実用テクニック」の本を読んでいれば解けるはず!という会長からのお達しだが・・・解けなかったらゴメンナサイゴメンナサイ。
【問題と解答】のリンク
【問題と解答】第21回未経験者大歓迎!誰でも働けるアットホームな職場ですシェル芸勉強会 – 上田ブログ
さて、私なりの回答例などをば。Macを使っての回答。
Q1
pdfファイルからテキストを抜き出す。とりあえずpdftotext
コマンドとか使えばいい?
$ pdftotext bba.pdf
Syntax Warning: Invalid Font Weight
あれ?何かエラーが出ちゃった??と思ってたら、
$ ls -l
total 40
-rw-r--r--+ 1 tashiro staff 13534 2 13 14:13 bba.pdf
-rw-r--r--+ 1 tashiro staff 61 2 13 23:51 bba.txt
$ cat bba.txt
群馬のシャブばばあ
hoge.txt[2016/02/09 22:30:32]
あら、テキストファイルが出来ていた。エラー出力を抑制するには-q
オプションを使い、標準出力に出すにはファイル名に-
を使えばいいらしい。
$ pdftotext -q bba.pdf -
群馬のシャブばばあ
hoge.txt[2016/02/09 22:30:32]
あとlessで見るといいという話もあったが、lessopenの設定とかが必要かも?時間がなかったので詳しく調べられていない。
Q2
Shift JIS(cp932)の固定長データの処理の問題。
データをざっと見て、35バイト毎に区切れば良さそうかな?と思ったが、下記のようにすると端末上ではへんてこりんな表示になってしまった。
しかし表示が乱れているだけだったようで、そのままnkfに通してしまえばよかったようだ。半角カナをそのまま出力する-x
を忘れてしまっていた・・・
$ cat anydata.cp932 | LANG=C gfold -b35 | nkf -wx
00000001ハナモゲギンコウ*******2144130511
00000002ハードバンク*********1144130188
00000003コドモギンコウ********2104130931
00000004ハタンギンコウ*********2344130008
00000005アンダーグラウンドギンコウ3314130900
00000006バミューダメンゼイギンコウ1234130981
追記
データの中身を確認する方法。odコマンドとiconvを使えばこんな感じで確認可能。nkfだと一部の表示がうまくいかなかった。ShiftJISの半角カナが濁点も1バイトだったりするのがわかりやすいかも。
$ LANG=ja_JP.SJIS od -t x1c anydata.cp932 | iconv -f CP932
0000000 30 30 30 30 30 30 30 31 ca c5 d3 b9 de b7 de dd
0 0 0 0 0 0 0 1 ハ ナ モ ケ ゙ キ ゙ ン
0000020 ba b3 2a 2a 2a 2a 2a 2a 2a 32 31 34 34 31 33 30
コ ウ * * * * * * * 2 1 4 4 1 3 0
0000040 35 31 31 30 30 30 30 30 30 30 32 ca b0 c4 de ca
5 1 1 0 0 0 0 0 0 0 2 ハ ー ト ゙ ハ
0000060 de dd b8 2a 2a 2a 2a 2a 2a 2a 2a 2a 31 31 34 34
゙ ン ク * * * * * * * * * 1 1 4 4
0000100 31 33 30 31 38 38 30 30 30 30 30 30 30 33 ba c4
1 3 0 1 8 8 0 0 0 0 0 0 0 3 コ ト
0000120 de d3 b7 de dd ba b3 2a 2a 2a 2a 2a 2a 2a 2a 32
゙ モ キ ゙ ン コ ウ * * * * * * * * 2
0000140 31 30 34 31 33 30 39 33 31 30 30 30 30 30 30 30
1 0 4 1 3 0 9 3 1 0 0 0 0 0 0 0
0000160 34 ca c0 dd b7 de dd ba b3 2a 2a 2a 2a 2a 2a 2a
4 ハ タ ン キ ゙ ン コ ウ * * * * * * *
0000200 2a 2a 32 33 34 34 31 33 30 30 30 38 30 30 30 30
* * 2 3 4 4 1 3 0 0 0 8 0 0 0 0
0000220 30 30 30 35 b1 dd c0 de b0 b8 de d7 b3 dd c4 de
0 0 0 5 ア ン タ ゙ ー ク ゙ ラ ウ ン ト ゙
0000240 b7 de dd ba b3 33 33 31 34 31 33 30 39 30 30 30
キ ゙ ン コ ウ 3 3 1 4 1 3 0 9 0 0 0
0000260 30 30 30 30 30 30 36 ca de d0 ad b0 c0 de d2 dd
0 0 0 0 0 0 6 ハ ゙ ミ ュ ー タ ゙ メ ン
0000300 be de b2 b7 de dd ba b3 31 32 33 34 31 33 30 39
セ ゙ イ キ ゙ ン コ ウ 1 2 3 4 1 3 0 9
0000320 38 31 0d 0a 0d 0a
8 1 \r \n \r \n
0000326
Q3
ようやく普通な?問題。今回福岡サテライト会場に参加された方は、この問題だけでも理解していただければ幸いある。いろいろやり方はあるが、会場で考えたのはこんなやり方。
まずはseqとsedでやっつけな日付っぽいリストを作成。やっつけ処理なので不正な日付も含まれるのに注意。
$ seq -w 0101 1231 | sed 's/^/2016/'
20160101
20160102
20160103
20160104
20160105
....
20161227
20161228
20161229
20161230
20161231
それをGNU dateコマンドに渡す。-f
オプションで読み込む日付のリストファイルを指定出来るが、GNU dateだと-
を指定すれば標準入力から読み込める(フィルタモード)。不正な日付についてはエラーメッセージが出るので、エラー出力をリダイレクトで捨てる。
$ seq -w 0101 1231 | sed 's/^/2016/' | gdate -f - '+%Y%m%d %a' 2> /dev/null
20160101 金
20160102 土
20160103 日
20160104 月
20160105 火
....
20161227 火
20161228 水
20161229 木
20161230 金
20161231 土
あとはgrepで日曜日だけを抜き出せばよい。
$ seq -w 0101 1231 | sed 's/^/2016/' | gdate -f - '+%Y%m%d %a' 2> /dev/null | grep '日$'
20160103 日
20160110 日
20160117 日
20160124 日
20160131 日
....
20161127 日
20161204 日
20161211 日
20161218 日
20161225 日
追記
MacやFreeBSDなどのBSD系OSに標準付属のdateコマンドだと、標準入力から日付リストを受けることが出来ない(フィルタモードが無い)。そこで、dateコマンドを下記のようにオプションを使うと、2016年1月1日から-vオプションで指定した日数後の日を表示出来る。
$ date -v+0d -j -f "%Y%m%d" 20160101 "+%Y%m%d %a"
20160101 金
$ date -v+1d -j -f "%Y%m%d" 20160101 "+%Y%m%d %a"
20160102 土
$ date -v+365d -j -f "%Y%m%d" 20160101 "+%Y%m%d %a"
20161231 土
BSD dateコマンドの上記の使い方をふまえて、下記のような回答が考えられる。MacやFreeBSDな方は、実際に実行して確認してほしい。ただしこのやり方は、dateコマンドが366回実行されるので遅いことに注意。
$ for i in {0..365}; do date -v+${i}d -j -f '%Y%m%d' 20160101 '+%Y%m%d %a'; done | grep '日$'
$ seq 0 365 | while read i; do date -v+${i}d -j -f '%Y%m%d' 20160101 '+%Y%m%d %a'; done | grep '日$'
$ seq 0 365 | xargs -I@ date -v+@d -j -f '%Y%m%d' 20160101 '+%Y%m%d %a' | grep '日$'
$ seq -f 'date -v+%gd -j -f "%%Y%%m%%d" 20160101 "+%%Y%%m%%d %%a"' 0 365 | sh | grep '日$'
$ seq 0 365 | sed 's/.*/date -v+&d -j -f "%Y%m%d" 20160101 "+%Y%m%d %a"/' | sh | grep '日$'
Q4
ユニケージのデータ更新処理につながる問題。Tukubaiコマンドを解禁させてもらう。sortコマンドの使い方が重要なので、解説を行いながら解いた。
正統派?
catとsortで2つのファイルをまとめて並べ替え。sortコマンドの-s
オプションで指定以外の列は並べ替えしないようにし、-k1,1
オプションで1列目をキーに並べ替える。
$ cat data newdata | sort -s -k1,1
001 あみだばばあ
002 砂かけばばあ
002 *******
003 ******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園
あとはTukubaiのgetlastコマンドを使って、1列目をキーにして最後の列のみを取り出す。
$ cat data newdata | sort -s -k1,1 | getlast 1 1
001 あみだばばあ
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園
変則?
こちらはちょっと変則的なやり方。Tukubaiのloopjコマンドで横に連結する。連結する際、データが無い部分は-d
オプションでスペースを入れてしまうのがミソ。
$ loopj -d' ' num=1 data newdata
001 あみだばばあ
002 砂かけばばあ *******
003 ****** 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園
あとはselfコマンドで1列目と最後の列を取り出す。
$ loopj -d' ' num=1 data newdata | self 1 NF
001 あみだばばあ
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園
Q5
テキストファイルの中に変なデータが混じっていることの確認方法。今回はodコマンドの使い方を解説した。私がよく使っているのは-t x1c
オプションを使って表示するやり方。1オクテット毎に16進数とキャラクタ表示をしてくれる。このやり方だとバイトオーダーの影響も受けないので便利。
$ od -t x1c a.bash
0000000 ef bb bf 23 21 2f 62 69 6e 2f 62 61 73 68 0a 0a
357 273 277 # ! / b i n / b a s h \n \n
0000020 65 63 68 6f 20 48 65 6c 6c 0a
e c h o H e l l \n
0000032
これでefbbbf
というのがファイルの最初に混じってるのがわかる。これは要するに「BOM付きUTF-8」ということだった。
$ od -t x1c b.bash
0000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 0a 6c 73 20
# ! / b i n / b a s h \n \n l s
0000020 cb 9c 2f 0a
˜ ** / \n
0000024
チルダがcb 9c
となっていて、何だか妙チクリンだということがわかる。
余談だが、MacやFreeBSDに付属するodコマンドは、マルチバイトの処理に対応している。こんな感じでわかりやすく表示してくれて便利。残念ながらGNU版のodコマンドはマルチバイト処理に対応してないようだ。
$ echo シェル芸勉強会 | od -t x1c
0000000 e3 82 b7 e3 82 a7 e3 83 ab e8 8a b8 e5 8b 89 e5
シ ** ** ェ ** ** ル ** ** 芸 ** ** 勉 ** ** 強
0000020 bc b7 e4 bc 9a 0a
** ** 会 ** ** \n
0000026
Q6
まずは問題の意味を理解するのに苦労した。要するに下記のようなテキスト処理をしろということだった。
a+h{5}(ho){10}[0-9]+
↑からこうじゃ↓
aa*hhhhhhohohohohohohohohoho[0-9][0-9]*
・・・解けなかった。途中までは下記のように・・・
$ cat extended | sed 's/a+/aa*/' | sed 's/\[0-9\]\+/[0-9][0-9]*/'
aa*h{5}(ho){10}[0-9][0-9]*
Q7
段落毎の文字数を数える。段落毎ってのをどうするか?よくやるのは一度全部連結して都合のいい場所で改行してしまうやり方。2つ目のsedコマンドは空行を削除している。
$ cat text | tr -d '\n' | gsed 's/ /\n/g' | sed '/^$/d'
恥の多い生涯を送って来ました。
自分には、人間の生活というものが、見当つかないのです。自分は東北の田舎に生れましたので、汽車をはじめて見たのは、よほど大きくなってからでした。自分は停車場のブリッジを、上って、降りて、そうしてそれが線路をまたぎ越えるために造られたものだという事には全然気づかず、ただそれは停車場の構内を外国の遊戯場みたいに、複雑に楽しく、ハイカラにするためにのみ、設備せられてあるものだとばかり思っていました。しかも、かなり永い間そう思っていたのです。ブリッジの上ったり降りたりは、自分にはむしろ、ずいぶん垢抜けのした遊戯で、それは鉄道のサーヴィスの中でも、最も気のきいたサーヴィスの一つだと思っていたのですが、のちにそれはただ旅客が線路をまたぎ越えるための頗る実利的な階段に過ぎないのを発見して、にわかに興が覚めました。
また、自分は子供の頃、絵本で地下鉄道というものを見て、これもやはり、実利的な必要から案出せられたものではなく、地上の車に乗るよりは、地下の車に乗ったほうが風がわりで面白い遊びだから、とばかり思っていました。
あとは各行の文字数を数える。どうやって数えるかだが、今回はwhileループからwcコマンドに渡して数えた。wcコマンドの-m
オプションは、マルチバイト処理でも文字数を数えてくれる。しかしこれは最後の改行までカウントしてしまってるのがダメなところだ。
$ cat text | tr -d '\n' | gsed 's/ /\n/g' | sed '/^$/d' | while read line; do echo $line | wc -m; done
16
354
104
Q8
最後は要するに、マルチーパートなメールデータが読めるか?という問題。データについて解説を行った。回答は会長とほぼ同じなので省略。
Content-Type: multipart/mixed; boundary=047d7b621ee6cf83c604cc276bb3【境界文字列】
--047d7b621ee6cf83c604cc276bb3【境界文字列の頭に--が付いたのがパートの始まり】
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
....
--047d7b621ee6cf83c604cc276bb3【境界文字列の頭に--が付いたのがパートの始まり】
Content-Type: image/jpeg; name="CHINJYU.JPG"
Content-Disposition: attachment; filename="CHINJYU.JPG"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_h8cn3pxc0
....
--047d7b621ee6cf83c604cc276bb3【境界文字列の頭に--が付いたのがパートの始まり】
Content-Type: image/jpeg; name="IMG_0965.JPG"
Content-Disposition: attachment; filename="IMG_0965.JPG"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_h8cn6ir71
....
H9a0pdUmvWljZ4ysQWFGaBeCFCtj054/DtXPLC3d47kwk56y2If7KW50y8YNBJLBJG1usb53f7JB
xk9On61jS6VNFJqFxdoIZYbWK6QALsnJbBjHYcc4GT2IHJrGhUevkZ1MNypPuf/Z
--047d7b621ee6cf83c604cc276bb3--【境界文字列の前後に--が付くと終了】
ということで今回も大変お疲れでござった。問題が解けることよりも、考え方の解説を重要視したつもりだったが伝わっただろうか??さて、初心者向けシェル芸勉強会も、後続を考えないといかんぞい・・・