2016/12/25

第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友の会、鳥海 秀一さんによる、 bash の使い方について学ぶ内容でした。

珍しく 変態的上級者向けな内容ではなく、鳥海さんの失敗談を交えて、初心者にも分かりやすい内容でした。
また、対話シェルのemacs/viモードそれぞれについて、基本的な操作方法や有用なキーバインド等が、解説されました。
そして、最後はやっぱり、お約束の端末破壊芸(?)もありました。
以下、気になったトピックを簡単に記載します。

端末上でのCtrl-sの用途

  • 画面スクロールを止めるためとの事。

  • どこかで聞いた話だけれど、端末の処理能力やバッファサイズが関係していたとか。今後確認しておく。

端末上で利用できる制御文字

  • Ctrl-hBackspace

  • Ctrl-m or jEnter

  • Ctrl-[Escape

  • Ctrl-iTab
    → どれもホームポジション付近にあるので、覚えておくとスムーズなキー操作が出来るようになる。
    → また、端末(シェル)以外にも、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が設定してある場合。

  1. コマンドライン上で何らかのコマンドを入力し、 Ctrl-e Ctrl-v を入力する。

  2. Vimが立ち上がり、バッファに先程入力したコマンドが表示される。

  3. コマンドを編集する。

  4. 編集し終わったら、上書き保存&Vimを終了する。

  5. 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

雑記

  • 今回のテーマは、エクシェル芸!
    → 会長調べによると、会場の9割ほどの人が、Officeファイルの実体はzipアーカイブであると、知っていたとの事。
    → シェル芸勉強会の参加者の皆様、優秀だ…​♥

  • ただ、今回の問題は、全体的に難易度が高めだった…​
    → 特に、問6が無茶苦茶難しくて、自分では解けなかったorz
    → 問6は、これまで出題されてきた問題の中でも、トップクラスの難易度だと個人的に思う。

  • 今回は、実際にはHTML/XMLタグの操作が多くて、基本コマンドだけだとちょっと大変だった…​
    → ただ、ベテランの方が使っていらっしゃったのだけれど、Perlの正規表現を使うと、タグ操作も簡単との事。
    → Perlの正規表現は、最短一致が使える事が大きい。
    → 正規表現は、BREとERE、それに awk の独自実装の3種類しか覚えていなかったけれど…​
    → (てか、僕は脳みその容量が貧弱なので、その3種類くらいしか覚えられないorz)
    → ここまで便利となると、Perlの正規表現も覚えてみたくなってきた…​!!


今回はOfficeファイルの改変がメインということで、いつもとは違った知識・操作が要求される、ちょっと風変わりな勉強会だったと思います。
問題演習が終わった時、何だかいつもよりずっと疲労感を感じましたが、それだけOfficeは扱いが大変だという事なのかもしれません。
とはいえ、上田会長が例を挙げたように、ちょっとしたドキュメントを大量生成する時には、大いに役に立ちそうです…​!!
勉強会を開催してくださった、上田会長をはじめとした日本UNIXユーザ会とUSP友の会の皆様、いつも本当にありがとうございます!!

Tags: シェル芸 Unix
このエントリーをはてなブックマークに追加