第26回シェル芸勉強会参加報告
2016年12月25日(日)に開催された、第26回シェル芸勉強会(正式名称:jus共催 第8回初心者の方角に向いて講師が喋るシェル勉強会(初心者向けとは言ってない)/第26回シェル芸勉強会及びエクシェル芸勉強会)に参加しました。
ただ、在住地の関係で直接会場へ伺うことは出来なかったため、Youtubeで配信してくださったライブ中継を利用して、遠隔で参加しました。
勉強会は、午前と午後の2部構成でした。
午前は、シェルに関する勉強会で、bashの使い方について学ぶ内容でした。
午後は、シェル芸勉強会で、シェル芸力を付けるための問題を解きました。
以下、勉強会の詳細を記します。
実行環境
Arch Linux 4.8.13-1
GNU bash 4.4.5
GNU coreutils 8.26-1
GNU diffutils 3.5-1
GNU findutils 4.6.0-2
grep (GNU grep) 2.26
sed (GNU sed) 4.2.2
gawk 4.1.4
tree v1.7.0
Zip 3.0 (July 5th 2008)
UnZip 6.00 of 20 April 2009
usp Personal Tukubai (20161101、 Open usp Tukubaiで代用可能)
シェルに関する勉強会
USP友の会、鳥海 秀一さんによる、 bash
の使い方について学ぶ内容でした。
珍しく 変態的上級者向けな内容ではなく、鳥海さんの失敗談を交えて、初心者にも分かりやすい内容でした。
また、対話シェルのemacs/viモードそれぞれについて、基本的な操作方法や有用なキーバインド等が、解説されました。
そして、最後はやっぱり、お約束の端末破壊芸(?)もありました。
以下、気になったトピックを簡単に記載します。
端末上でのCtrl-sの用途
画面スクロールを止めるためとの事。
どこかで聞いた話だけれど、端末の処理能力やバッファサイズが関係していたとか。今後確認しておく。
端末上で利用できる制御文字
Ctrl-h
→Backspace
Ctrl-m
orj
→Enter
Ctrl-[
→Escape
Ctrl-i
→Tab
→ どれもホームポジション付近にあるので、覚えておくとスムーズなキー操作が出来るようになる。
→ また、端末(シェル)以外にも、Unixと関連の深いソフトウェアなら、上記の操作が利用できることも。
→ ただ、Ctrl-[
に関しては、JISキーボードだと位置が遠いので、ちょっと使いにくいかも…
viモードの利点・欠点
利点
→ viのキーバインドをほぼそのまま使えるので、(vi/Vimユーザなら特に)学習コストが低い。
→ ノーマルモードに切り替えれば、viの強力な編集機能が利用できるので、コマンドラインの修正が容易。欠点
→ コマンドラインは基本的に一行しか扱わないため、viの豊富な移動機能を活かしにくい。
→ Vimのテキストオブジェクトは利用できない(あくまで「vi」モードなので)。
→ 一部のシェルでは、viモードに不具合がある。 (e.g. mkshにてviモードを使用した際の問題点まとめ(Ver.R52時点) - Terrulam)
また、僕は比較的マイナーである対話シェルのviモードを常用してますので、今後利用したい人の参考として、役に立つ設定等を記しておきます。
プロンプト上に現在のモード状態を表示する。
.bashrcに
bind 'set show-mode-in-prompt on'
を記入する。もしくは、.inputrcに
set show-mode-in-prompt
を記入する。
→ こちらの設定は、readline
に対応しているプログラム(e.g. 対話Python等)にも反映される。インサートモードは
+
、ノーマルモードは:
と表示されるようになる。
→ Bash 4.4以上なら、(ins)
or(cmd)
と表示される。
(以下の設定は、emacsモードでも使用可能)
インサートモード時、 Ctrl-[pn]
で、ヒストリのインクリメンタルサーチをする。
.bashrcに以下の内容を記入する。
bind '"\C-p": history-search-backward' bind '"\C-n": history-search-forward'
インサートモード時、
Ctrl-e Ctrl-v
で、エディタを用いてコマンドラインを編集する。.bashrcに以下の内容を記入する。
bind '"\C-e\C-v": edit-and-execute-command'
以下、動作の解説。
例えば、環境変数 EDITOR
にVimが設定してある場合。
コマンドライン上で何らかのコマンドを入力し、
Ctrl-e Ctrl-v
を入力する。Vimが立ち上がり、バッファに先程入力したコマンドが表示される。
コマンドを編集する。
編集し終わったら、上書き保存&Vimを終了する。
Vimにて編集したコマンドが実行される。
この設定は、複雑なコマンドを入力する場合なんかに、便利だと思う!
第26回シェル芸勉強会
問題文および模範解答は、以下のURLから。
https://blog.ueda.asia/?p=8833
問1
各種Officeファイルを展開し、中に含まれるファイルを確認する問題。
第一問目ということで、シンプルな内容。
全ファイルを unzip
で展開して、 tree
コマンドで構成を確認する。
ただ、単純に展開するだけだと、重複ファイルが発生してしまうため、展開ディレクトリをファイル毎に分けておく。
01 #!/bin/sh
02
03 ls *.*x | # Officeファイルの列挙
04 awk -F. '{print "unzip -o -c",$1,$0}' | # unzipコマンドの生成
05 sh # コマンドの実行
06
07 tree # ファイル構成の確認
08
09 find . -maxdepth 2 -type d | # ディレクトリ構造の出力
10 grep -E 'ppt|xl|word' | # ファイルタイプ判別情報の抽出
11 awk -F/ '{print "zip -r",$2"."$3".after",$2}' | # zipコマンドの生成
12 sh # コマンドの実行
以下、コピペ実行用のワンライナーコード。
$ ls *.*x | awk -F. '{print "unzip -o -d",$1,$0,"&& tree",$1,"&& (cd "$1"; zip -r ../"$1".new."$2" ./*)"}' | sh
ワンライナーでやろうとしたら、むしろ逆に複雑になってしまった…
問2
PowerPointファイルから、特定の単語の個数を数えるする問題。
初めは、単純に unzip -p
して、その出力から「危険」を grep
で抽出すれば良いと考えていたのだけれど…
全ファイルを出力してしまうと、非テキストな出力がされた時点で grep
での抽出が終わってしまう。
そこで、スライドの文字データが含まれているファイル、"slides*.xml"のみを抽出することにする。
01 #!/bin/sh
02
03 unzip -p 20141019OSC_LT.pptx '*/slides*.xml' | # アーカイブから"slides*.xml"のみを出力
04 grep -o '危険' | # 文字列「危険」の抽出
05 grep -c '' # レコード数の出力
以下、コピペ実行用のワンライナーコード。
$ unzip -p 20141019OSC_LT.pptx '*/slides*.xml' | grep -o '危険' | grep -c ''
問3
PowerPointスライドに含まれる画像を抽出し、アーカイブ化する問題。
シンプルな問題。unzip
でアーカイブを展開した後、 find
等で画像ファイルのみを抽出、最後に再度アーカイブ化すればOK。
01 #!/bin/sh
02
03 mkdir img # 画像ファイル用ディレクトリの作成
04
05 unzip -d slide 20141019OSC_LT.pptx # スライドファイルの展開
06
07 find slide -type f | # ファイルパスの列挙
08 grep -E '\.jpe+g|png$' | # 画像ファイルレコードの抽出
09 xargs -I@ cp @ img # ファイルのコピー
10
11 zip -r img.zip img # 画像ファイルをアーカイブ化
以下、コピペ実行用のワンライナーコード。
$ mkdir img && unzip -d slide 20141019OSC_LT.pptx && find slide -type f | grep -E '\.jpe+g|png$' | xargs -I@ cp @ img && zip -r img.zip img
問4
スライドに含まれる文字列をスクレイピングする問題。
単純に7ページ目のスライドを抽出し、中身のXMLをフィルタで整形していくだけ。
01 #!/bin/sh
02
03 unzip -p 20141019OSC_LT.pptx '*/slide7.xml' | # 7ページ目のスライドの中身を出力
04 grep -o '<a:t>[^>]*</a:t>' | # テキスト部分の抽出
05 sed 's/<[^>]*>//g' | # 出力の整形
以下、コピペ実行用のワンライナーコード。
$ unzip -p 20141019OSC_LT.pptx '*/slide7.xml' | grep -o '<a:t>[^>]*</a:t>' | sed 's/<[^>]*>//g'
問5
ここからはExcelについての問題。
Excelファイルのシートに含まれるデータ列を、SSV形式で出力する問題。
段々と難しくなってきた…
今回も、該当するシートファイルを抽出&出力して、XMLデータをフィルタで整形していく。grep -o
の正規表現部分は、最短一致が利用できるPerlの拡張正規表現だと、もっとシンプルにできるとの事。
01 #!/bin/sh
02
03 unzip -p graph.xlsx '*/sheet1.xml' | # シートファイルの出力
04 grep -o '<c r="[A-Z]*[0-9]*"><f[^>]*/><v>[^>]*</v>' | # セルデータ部分を抽出
05 sed 's/<[^>]*>//g' | # XMLタグの除去
06 xargs -n 2 # 2列n行に整形
以下、コピペ実行用のワンライナーコード。
$ unzip -p graph.xlsx '*/sheet1.xml' | grep -o '<c r="[A-Z]*[0-9]*"><f[^>]*/><v>[^>]*</v>' | sed 's/<[^>]*>//g' | xargs -n 2
xargs
を使った行列変換の処理が出てくると、何だかホッとしますヾ(*´∀`*)ノ
問6
問5と同様の問題。
ただし、問5とは異なり、シート内にマルチバイト文字のデータが含まれている。
この問題、これまで出題された問題の中でも、最高クラスの難易度だと思う…
Excelの仕様として、シート内にマルチバイト文字が含まれている場合、セル値はシートファイルとは別のファイルに分離されてしまうそう。
シートファイルに記載されている参照情報を、セル値が記載されているファイルの中身に結びつければ、求める出力が得られそうなのだけれど…
正直、中身のデータがあまりに複雑(というよりも汚い…)すぎて、自力では出来なかったorz
とりあえず、商用版Tukubaiの便利コマンド、 rexcelx
を使って、お茶を濁しておく…
1 #!/bin/sh
2
3 rexcelx 1 hanshin.xlsx
以下、コピペ実行用のワンライナーコードと出力。
$ rexcelx 1 hanshin.xlsx
@ 42522 42561
1 真弓 マユミ
2 弘田 北村
3 バース バース
4 掛布 掛布
5 岡田 佐野
6 佐野 木戸
7 平田 ヒラt
8 木戸 永尾
9 ゲイル 池田
問7
今度はWordファイルの問題。
Wordファイルの中身を改変する問題。
他のOfficeファイルと同様に、ファイルを展開&該当するデータを操作すればOK。
ただ、最後に改変Wordファイルを作成する際、作業ディレクトリに注意しないと、正常なファイルが作成できない。
→ (勉強会の時、 cd
を忘れていて出来なかったorz)
01 #!/bin/sh
02
03 unzip -d cert certificate.docx # Wordファイルの展開
04
05 sed -i 's/WINNER/殿/g' cert/word/document.xml # 該当テキストの置換
06
07 cd cert # 作業ディレクトリの変更
08 zip -r ../new.docx ./* # 改変Wordファイルの作成
以下、コピペ実行用のワンライナーコード。
$ unzip -d cert certificate.docx && sed -i 's/WINNER/殿/g' cert/word/document.xml && (cd cert; zip -r ../new.docx ./*)
問8
問7の発展系。テンプレファイルと名前リストを用いて、複数のWordファイルを作成する問題。
これも、大体の流れは問7とほぼ同じ。
名前リストを加工して、名前毎にWordファイルを生成するコマンドを作れば、あとは実行するだけ。
01 #!/bin/sh
02
03 cat list.txt | # 名前リストの出力
04 sed 's/.*/unzip -d & certificate.docx/' | # コマンドの生成 その1
05 awk '{print $0,"&&","sed -i s/WINNER/"$3"/g",$3"/word/document.xml","&&","(cd",$3"; zip -r ../"$3".docx","./)"}' | # コマンドの生成 その2
06 sh # コマンドの実行
以下、コピペ実行用のワンライナーコード。
$ cat list.txt | sed 's/.*/unzip -d & certificate.docx/' | awk '{print $0,"&&","sed -i s/WINNER/"$3"/g",$3"/word/document.xml","&&","(cd",$3"; zip -r ../"$3".docx","./)"}' | sh
参照Webサイト
Doorkeeper - jus共催 第8回初心者の方角に向いて講師が喋るシェル勉強会(初心者向けとは言ってない)/第26回シェル芸勉強会及びエクシェル芸勉強会
→ 勉強会の概要。シェル芸 のライブ ストリーム(午後)
→ 今回の勉強会の動画配信(アーカイブ)。
Different bash prompt for different vi editing mode? - Stack Overflow
→ viモード時にプロンプトにモード状態を表示する設定方法。
雑記
今回のテーマは、エクシェル芸!
→ 会長調べによると、会場の9割ほどの人が、Officeファイルの実体はzipアーカイブであると、知っていたとの事。
→ シェル芸勉強会の参加者の皆様、優秀だ…♥ただ、今回の問題は、全体的に難易度が高めだった…
→ 特に、問6が無茶苦茶難しくて、自分では解けなかったorz
→ 問6は、これまで出題されてきた問題の中でも、トップクラスの難易度だと個人的に思う。今回は、実際にはHTML/XMLタグの操作が多くて、基本コマンドだけだとちょっと大変だった…
→ ただ、ベテランの方が使っていらっしゃったのだけれど、Perlの正規表現を使うと、タグ操作も簡単との事。
→ Perlの正規表現は、最短一致が使える事が大きい。
→ 正規表現は、BREとERE、それにawk
の独自実装の3種類しか覚えていなかったけれど…
→ (てか、僕は脳みその容量が貧弱なので、その3種類くらいしか覚えられないorz)
→ ここまで便利となると、Perlの正規表現も覚えてみたくなってきた…!!
今回はOfficeファイルの改変がメインということで、いつもとは違った知識・操作が要求される、ちょっと風変わりな勉強会だったと思います。
問題演習が終わった時、何だかいつもよりずっと疲労感を感じましたが、それだけOfficeは扱いが大変だという事なのかもしれません。
とはいえ、上田会長が例を挙げたように、ちょっとしたドキュメントを大量生成する時には、大いに役に立ちそうです…!!
勉強会を開催してくださった、上田会長をはじめとした日本UNIXユーザ会とUSP友の会の皆様、いつも本当にありがとうございます!!