第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友の会の皆様、いつも本当にありがとうございます!!