「第26回シェル芸勉強会 大阪サテライト」の記録
はじめに
12月25日(日)に開催された「第26回シェル芸勉強会 大阪サテライト」に参加しました。
朝9時45分から夜18時までひたすらsh行に打ち込む一日でした。
……シェル芸人の朝は早い。
メイン会場および他サテライト会場
各会場の様子
- jus共催 第8回初心者の方角に向いて講師が喋るシェル勉強会(初心者向けとは言ってない)/第26回シェル芸勉強会及びエクシェル芸勉強会 - Togetterまとめ
- 第26回 #シェル芸 勉強会に参加してきました - 職業プログラマの休日出勤
- 第26回シェル芸勉強会へ遠隔参加 - 日々之迷歩
問題ならびに模範解答
ライブストリーム(YouTube)
午前の部: シェルに関する勉強会
黒い画面と戯れよう
講師: 鳥海秀一さん
- 黒い画面とは
- キーボード入力と画面の文字表示のみでコンピュータの操作を行うUIのこと
- 黒い画面怖い
CTRL+S
・CTRL+Q
: コンピュータが遅かった時代、スクロールを止めて出力を見るためvi
:CTRL+Z
……fg
を使わないと戻れない
- 攻略の方針
- 遊び心: 遊ぶようなつもりで
- 分割統治: キーボードと黒い画面
- キーボードとは
- 指で意思をコンピュータに伝える
- 指は人間の部位の中では数が多く、器用で便利
- 使いこなすには努力が必要
- キーバインドを覚える
- アプリケーション毎に異なる
- Unixではvi風とemacs風の2つが有名
bash
のキーバインド- 端末ドライバ
- キーボードとOS間のデータフローを処理
stty
で設定の読込/変更stty -a
で端末設定を確認
- Readlineライブラリ
- テキストベースのインターフェイス用にGNUで開発されたライブラリ
bash
のコマンドライン編集インターフェイス- viモードとemacsモードの両方にデフォルトの編集機能を提供
- モード確認には
set -o
- 端末ドライバ
- emacsモードのキーバインド
- 移動コマンド
CTRL+B
: 後方に1文字移動CTRL+F
: 前方に1文字移動ESC+B
: 後方に1ワード移動ESC+F
: 前方に1ワード移動CTRL+A
: コマンドラインの先頭に移動CTRL+E
: コマンドラインの末尾に移動
- 削除、取出コマンド
BACKSPACE
: 後方に1文字削除CTRL+D
: 前方に1文字削除CTRL+W
: 後方に1ワード削除ESC+D
: 前方に1ワード削除CTRL+K
: コマンドラインの末尾まで削除CTRL+U
: コマンドラインの先頭まで削除CTRL+Y
: 最後に削除したものを取り出す
- 履歴コマンド
CTRL+P
: 前の行へ移動CTRL+N
: 次の行へ移動CTRL+R
: 後方検索を実行CTRL+S
: 前方検索を実行ESC+<
: 履歴ファイルの先頭行に移動ESC+>
: 履歴ファイルの最終行に移動
- 補完コマンド
TAB
: テキストの標準的な補完を試みるESC+?
: 補完候補の一覧を表示ESC+/
: ファイル名としての補完を試みるESC+~
: ユーザ名としての補完を試みるESC+@
: ホスト名としての補完を試みるESC+|
: コマンドとしての補完を試みる
- その他のコマンド
CTRL+J
:RETURN
と同じCTRL+L
: 画面を消去CTRL+V
: 次の文字を逐語的に挿入CTRL+[
:ESC
と同じESC+U
: ポイント後のワードを大文字にするESC+L
: ポイント後のワードを小文字にする
- 移動コマンド
- viモードのキーバインド
- 編集コマンド(入力モード)
BACKSPACE
: 前の文字を削除CTRL+H
: 前の文字を削除CTRL+W
: 前のワードを削除CTRL+U
: コマンドの先頭まで削除ESC
: 制御モードに移るCTRL+[
: 制御モードに移る
- 移動コマンド(制御モード)
h
: 左に1文字移動l
: 右に1文字移動w
: 右に1ワード移動b
: 左に1ワード移動0
: コマンドラインの先頭へ移動$
: コマンドラインの末尾へ移動
- 入力モードへの移行コマンド(制御モード)
i
: 現在の文字の前にテキストを挿入a
: 現在の文字の後にテキストを挿入I
: コマンドラインの先頭にテキストを挿入A
: コマンドラインの末尾にテキストを挿入R
: 既存のテキストを上書き
- 削除コマンド(制御モード)
x
(dl
): 現在の文字を削除X
(dh
): 現在の前の文字を削除db
: 後方に1ワード削除dw
: 前方に1ワード削除D
(d$
): コマンドラインの末尾まで削除d0
: コマンドラインの先頭まで削除
- 取出コマンド(制御モード)
p
: 最後に削除したものを現在の文字の後に挿入P
: 最後に削除したものを現在の文字の前に挿入CTRL+Y
: 最後に削除したものを現在の文字の前に挿入
- 履歴コマンド(制御モード)
k
(-
): 後方に1行移動j
(+
): 前方に1行移動/string
: 後方に__string__を検索?string
: 前方に__string__を検索n
: 前回と同じ方向に検索を繰り返すN
: 前回と逆の方向に検索を繰り返す
- 文字検索コマンド(制御モード)
fx
: 次の__x__へ移動Fx
: 前の__x__へ移動tx
: 次の__x__の1つ前に移動Tx
: 前の__x__の1つ後に移動;
: 最後の文字検索を繰り返す,
: 最後の文字検索を逆方向に繰り返す
- 補完コマンド(制御モード)
\
: 補完を試みる*
: 補完を試みる=
: 補完候補の一覧を表示
- その他のコマンド(制御モード)
~
: 現文字の大文字と小文字を入れ替える_
: 前のコマンドの最後のワードを付け足す#
: コマンドラインの前に__#__(コメント記号)を付け、それを履歴ファイルに書き込む
- 編集コマンド(入力モード)
bash
のキーバインドの覚え方- 何度も繰り返して実行してみる
bind -p
や、bind -P
の結果を検索
bash
のキーバインドを変えてみようbind '"a": self-insert'
bind '"a": '
bind '"a": "b"'
bind '"a": clear-screen'
休憩
昼食の時間を利用して、T.Motooka(@t_motooka)さんによるミニ勉強会が行われました。
- 「バイナリーチラリー」を使ったバイナリイントロクイズ
- エクシェル芸の予習: xlsxファイルのファイルフォーマットについて
午後の部: シェル芸勉強会
- いずれの問題も、Debian 8「jessie」の32ビットPC版で解答しています。
- 使用OSによっては、
sort
を実行する言語環境をLANG=C
にする必要があるかも知れません。
A1: MS Officeファイルの中を見る
$ ls *.{xlsx,docx,pptx} | xargs -I@ bash -c "unzip -q @ -d @-DIR; ls @-DIR/* >> FILES.TXT; (cd @-DIR; zip -qr ../@ .); rm -fR @-DIR"; cat FILES.TXT
20141019OSC_LT.pptx-DIR/[Content_Types].xml
20141019OSC_LT.pptx-DIR/_rels:
20141019OSC_LT.pptx-DIR/docProps:
(...略...)
slideMasters
slides
tableStyles.xml
theme
viewProps.xml
この問題の解き方は、
ls
でxlsx・docx・pptxファイル名を取得xargs -I 置換文字列
で各ファイルごとに次のコマンド群をbash
に実行させるunzip [圧縮ファイル] -d [展開先ディレクトリ]
で、各ファイルを「ファイル名-DIR
」に展開ls
の出力をFILES.TXT
に保存zip -r [圧縮ファイル] [圧縮するディレクトリ]
で元のファイルに戻すrm -fR
で後片付け
cat
でFILES.TXT
を出力
という手順になっています。
なお、zip
実行時には-q
オプションを付けて、不要な出力を抑えています。
ちなみに、手順2.2.のls @-DIR/*
をtree @-DIR
に置き換えると、より分かりやすいファイルリストが出来上がります。
$ ls *.{xlsx,docx,pptx} | xargs -I@ bash -c "unzip -q @ -d @-DIR; tree @-DIR >> FILES.TXT; (cd @-DIR; zip -qr ../@ .); rm -fR @-DIR"; cat FILES.TXT
20141019OSC_LT.pptx-DIR
├── [Content_Types].xml
├── _rels
├── docProps
│ ├── app.xml
(...略...)
├── theme
│ └── theme1.xml
└── viewProps.xml
12 directories, 37 files
A2: スライド内の単語「危険」の出現回数を求める
訂正: 当日の解答(1/2)・当日の解答(2/2)に誤りがありましたので、次の通り訂正します。
$ unzip -q 20141019OSC_LT.pptx -d tmp; grep -lr '危険' tmp/ppt/slides | xargs -I@ sed -i 's/\(危険\)/\n\1\n/g' @; grep -cr '危険' tmp/ppt/slides | awk -F: '$2!=0{sum+=$2;print}END{print "合計: "sum}'; rm -fR tmp
tmp/ppt/slides/slide5.xml:1
tmp/ppt/slides/slide1.xml:1
tmp/ppt/slides/slide8.xml:1
tmp/ppt/slides/slide28.xml:2
tmp/ppt/slides/slide12.xml:1
tmp/ppt/slides/slide6.xml:1
tmp/ppt/slides/slide15.xml:1
tmp/ppt/slides/slide4.xml:1
tmp/ppt/slides/slide19.xml:1
tmp/ppt/slides/slide20.xml:1
tmp/ppt/slides/slide30.xml:1
tmp/ppt/slides/slide33.xml:5
合計: 17
スライドのデータファイルは[展開先]/ppt/slides
ディレクトリに格納されています。
この問題の解き方は、
unzip [圧縮ファイル] -d [展開先ディレクトリ]
でtmp
ディレクトリに展開grep -lr パターン [ディレクトリ]
でtmp/ppt/slides
ディレクトリにある、行に「危険」という単語を含むファイル名を得る- 2.で得たファイル名リストについて、
grep -c
はマッチの個数を行単位でチェックするため、sed
で「危険」の前後に改行を挿入する grep -cr パターン [ディレクトリ]
でtmp/ppt/slides
ディレクトリにある各ファイルについて、パターン「危険」にマッチする行数(=個数)を得るawk
で第2フィールドの合計(=出現回数)を求め、出力rm -fR
で後片付け
という手順になっています。
しかし、単純に出現回数を得るのであれば、grep
の
-o, –only-matching
マッチする行のマッチした部分だけを (それが空文字列でなければ) 表示します。
マッチした各文字列は、それぞれ別の行に書き出します。
というオプションを利用した
$ unzip -q 20141019OSC_LT.pptx -d tmp; grep -or '危険' tmp/ppt/slides | wc -l; rm -fR tmp
17
で十分でしょう。
A3: スライドから画像を抽出し、ZIPファイルに圧縮
$ unzip -q 20141019OSC_LT.pptx -d tmp; (cd tmp/ppt; zip -q ../../media.zip media/*.*); rm -fR tmp
スライド内の画像ファイルは[展開先]/ppt/media
ディレクトリに格納されていますので、このディレクトリごとzip
で圧縮すればOKです。
A4: スライドのスクレイピング
$ unzip -p 20141019OSC_LT.pptx ppt/slides/slide7.xml | grep -Po '<a:p>.+?</a:p>' | sed 's/<[^<]\+>//g' | sed '/^$/d'
戦果(?)
初日だけで見知らぬ方のマシン3台轟沈
その他自爆者多数
Docker上で試したらホストマシン沈黙の報告
自分の本がサイト経由で1冊だけ売れた
フォロワーが1人減った
2014/10/19
OSC Tokyo/Fall 2014
7
この問題の解き方は、
unzip -p [圧縮ファイル] [特定のファイル]
で、スライド7ページ目のXMLデータを出力- 正規表現で最短量指定子の「+?」が使えるように
-P
(--perl-regexp
)オプションを付けたgrep -o
で、パラグラフ部分(a:p要素)を抽出 sed
でXMLタグと空行を削除
という手順になっています。
A5: ワークシートをSSV(スペース区切り)形式で出力――その1
$ unoconv -d spreadsheet -f csv --stdout graph.xlsx | tr ',' ' '
0 -5
0.5 -7.375
1 -14
1.5 -24.125
2 -37
(...略...)
9 -86
9.5 -50.125
10 -5
10.5 50.125
11 116
unoconv
を使えば簡単に解けますが、それだけでは面白みに欠けますのでA4の手法を応用した
$ unzip -p graph.xlsx xl/worksheets/sheet1.xml | grep -Po '<v>.+?</v>' | sed 's/<[^<]\+>//g' | xargs -n2
0 -5
0.5 -7.375
1 -14
1.5 -24.125
2 -37
(...略...)
9 -86
9.5 -50.125
10 -5
10.5 50.125
11 116
unzip -p
でワークシートのXMLデータを出力grep -Po
で各セルの値(v要素)を抽出sed
でXMLタグを除去xargs -n2
で1行につき2ヶの値を出力
のような普通(?)のシェル芸も別解として挙げておきます。
A6: ワークシートをSSV(スペース区切り)形式で出力――その2
$ unoconv -d spreadsheet -f csv --stdout hanshin.xlsx | tr ',' ' '
06月01日 07月10日
1 真弓 真弓
2 弘田 北村
3 バース バース
4 掛布 掛布
5 岡田 佐野
6 佐野 木戸
7 平田 平田
8 木戸 永尾
9 ゲイル 池田
A5と同様、unoconv
を使えば簡単ですが、これを普通(?)のシェル芸で解くと一気に難しくなります。
最終的なシェル芸は、
$ awk 'NR<=15{T[$1]=$2}NR==16{print $0}NR>=17{print $1,T[$2],T[$3]}' <(unzip -p hanshin.xlsx xl/sharedStrings.xml | grep -Po '<si>.+?</si>' | sed 's/<si><t>//;s/<\/t>.*//' | awk '{print NR-1,$1}') <(unzip -p hanshin.xlsx xl/worksheets/sheet1.xml | grep -Po '<row.+?</row>' | sed 's/<[^<]\+>/ /g;s/ \+/ /g')
42522 42561
1 真弓 真弓
2 弘田 北村
3 バース バース
4 掛布 掛布
5 岡田 佐野
6 佐野 木戸
7 平田 平田
8 木戸 永尾
9 ゲイル 池田
になりますが、手順が非常に複雑なため、大きく3つの部分に分解して説明します。
-
文字列置換用テーブルの生成
$ unzip -p hanshin.xlsx xl/sharedStrings.xml | grep -Po '<si>.+?</si>' | sed 's/<si><t>//;s/<\/t>.*//' | awk '{print NR-1,$1}' > TABLE $ cat TABLE 0 真弓 1 弘田 2 バース 3 掛布 4 岡田 5 佐野 6 平田 7 木戸 8 ゲイル 9 北村 10 掛布 11 佐野 12 木戸 13 永尾 14 池田
ワークシートで表示されるそれぞれの文字列は、
xl/sharedStrings.xml
のsi要素の子要素であるt要素に格納されています。そして、ワークシート
xl/worksheets/sheet1.xml
の方では、<c r="B2" t="s"><v>0</v></c>
のように、c要素の子要素であるv要素の値(0から始まるインデックス番号)に置き換えられています。手順については、A5の別解と同じくA4の手法を応用して、最後の
awk '{print NR-1,$1}'
の部分でインデックス番号を生成しています。 -
ワークシートのデータの抽出
$ unzip -p hanshin.xlsx xl/worksheets/sheet1.xml | grep -Po '<row.+?</row>' | sed 's/<[^<]\+>/ /g;s/ \+/ /g' > SHEET $ cat SHEET 42522 42561 1 0 0 2 1 9 3 2 2 4 3 10 5 4 11 6 5 12 7 6 6 8 7 13 9 8 14
ここでもA4の手法を応用して各セルのデータを抽出しています。
-
ワークシートのデータ置換と出力
$ awk 'NR<=15{T[$1]=$2}NR==16{print $0}NR>=17{print $1,T[$2],T[$3]}' TABLE SHEET 42522 42561 1 真弓 真弓 2 弘田 北村 3 バース バース 4 掛布 掛布 5 岡田 佐野 6 佐野 木戸 7 平田 平田 8 木戸 永尾 9 ゲイル 池田
1.で生成した
TABLE
と、2.で生成したSHEET
を順にawk
に読み込ませます。TABLE
の部分に相当する1〜15行目では、第1フィールドをキー、第2フィールドを値とした連想配列Tに置換用テーブルを格納しています。そして、
SHEET
の部分に相当する16行目以降では、ヘッダとなる16行目を除いて「第1フィールド 連想配列Tの要素 連想配列Tの要素」というレイアウトで出力を行っています。
これら3つのシェル芸を、プロセス置換(<( )
)を使って1つにまとめたものが先程の
awk 'NR<=15{T[$1]=$2}NR==16{print $0}NR>=17{print $1,T[$2],T[$3]}' <(unzip -p hanshin.xlsx xl/sharedStrings.xml | grep -Po '<si>.+?</si>' | sed 's/<si><t>//;s/<\/t>.*//' | awk '{print NR-1,$1}') <(unzip -p hanshin.xlsx xl/worksheets/sheet1.xml | grep -Po '<row.+?</row>' | sed 's/<[^<]\+>/ /g;s/ \+/ /g')
となります。
A7: 文字のはめ込み――その1
$ unzip -q certificate.docx -d tmp && sed -i 's/WINNER/シェル芸人/g;s/TODAY/'"$(date +%F)"'/g' tmp/word/document.xml; (cd tmp; zip -qr ../シェル芸人.docx .) && rm -fR tmp
$ docx2txt シェル芸人.docx - | uniq
優秀賞
2016-12-25
PUBPOSITION PUBNAME
あなたは優秀な成績を修めましたのでここに表彰します
シェル芸人 殿
この問題の解き方は、
unzip [圧縮ファイル] -d [展開先ディレクトリ]
でcertificate.docx
をtmp
ディレクトリに展開sed -i
でtmp/word/document.xml
内の「WINNER」と「TODAY」をそれぞれ置換し、上書き保存zip -r [圧縮ファイル] [圧縮するディレクトリ]
でシェル芸人.docx
を生成rm -fR
で後片付け
という手順になっています。
A8: 文字のはめ込み――その2
$ cat list.txt | xargs -I@ bash -c "unzip -q certificate.docx -d tmp && sed -i 's/WINNER/@/g;s/TODAY/'"$(date +%F)"'/g' tmp/word/document.xml; (cd tmp; zip -qr ../@.docx .) && rm -fR tmp"
$ cat list.txt | xargs -I@ bash -c "docx2txt @.docx - | uniq"
優秀賞
2016-12-25
PUBPOSITION PUBNAME
あなたは優秀な成績を修めましたのでここに表彰します
シェル芸おじさん 殿
優秀賞
2016-12-25
PUBPOSITION PUBNAME
あなたは優秀な成績を修めましたのでここに表彰します
シェル芸野郎 殿
優秀賞
2016-12-25
PUBPOSITION PUBNAME
あなたは優秀な成績を修めましたのでここに表彰します
変態シェル芸豚野郎 殿
A7の応用編です。
cat list.txt
で得た名前のリストを、xargs -I 置換文字列
でA7のシェル芸をbash
に読み込ませて実行させています。
LT大会
Excelでもコマンド実行がしたい
発表者: nmrmsys(@nmrmsys)さん
- 「ExSQell」の紹介
- Excelのシート上にあるシェルコマンドやSQL文を実行し、その出力をシート上で利用できる
- 機能強化: リダイレクト機能が加わる
- 機能強化: SSHを使ったリモートコマンド実行機能が加わる
- 機能強化:
sudo
が利用可能になる
Hyper(TM)でエキサイティングなシェル芸ライフ
発表者: くんすと(@kunst1080)さん
FUSEで繋がる世界
発表者: so(@3socha)さん
- 「FUSE」とは
- 仮想ファイルシステム作成用インターフェイス
- Plan 9由来
- 利用例: procfs・sshfs・s3fs/goofy・NTFS-3G・GmailFSなど
- ユーザ空間で動作するため、安全で拡張性も高い
- Googleカレンダー用カレンダーFSを実装してみる
- ファイルシステムでズンドコキヨシ - Qiitaの紹介
漢字バナー芸
発表者: MSR(@msr386)さん
- 「バナー芸」とは
toilet
で漢字が使えるようにする- フォントデータの形式
- 漢字のフォントデータを自動生成する方法
追加: バナー芸
発表者: 社畜(9か月)@ぬるり(@null_ref_eng)さん
echo "___\\\\(^o^)/___オワタ___" | sed ':a;p;s/\(.\)\(.*\)/\2\1/;/^a/!b a' | xargs -I{} toilet -F border --gay {}
おわりに
bash
のキーバインドといえば、今までemacsモードの移動コマンド程度しか使っておらず、キーボード入力時に結構ムダな動作をしている自覚があったので、午前の部の講義で
紹介されたキーバインド一覧をせめて半分程度でも覚えてみようかと思います。
そういうことでライブストリームからキーバインドを全て書き出してみましたので、あくまでも自分用に作ったものではありますがチートシート代わりに使っていただければ幸いです。
午後のエクシェル芸では、大阪サテライト会場の参加者全員が
- 「Software Design 2017年1月号」を購入している
- MS Officeのファイルが、XMLファイルや画像ファイルなどを
zip
で圧縮したものであることを知っている
という恐るべき事実が判明したのが印象的でした。
最後に、
- 大阪サテライトの主催をされている、くんすと(@kunst1080)さん、T.Motooka(@t_motooka)さん
- 大阪サテライト会場を提供してくださっている、フェンリル株式会社 大阪本社様
- 午前の部の講師を務めてくださった、鳥海秀一さん
- Ryuichi Ueda(@ryuichiueda)さんをはじめとする、メイン会場スタッフの皆さん
に改めてお礼を申し上げます。ありがとうございました。
……エクシェル芸はムズいが役に立つ。