【問題と解答】第26回シェル芸勉強会及びエクシェル芸勉強会

Sun Dec 25 16:40:09 JST 2016 (modified: Sun Oct 1 10:50:27 JST 2017)
views: 2651, keywords:Excel,PowerPoint,Word,シェル芸,エクシェル芸,シェル芸勉強会 この記事は最終更新日が6年以上前のものです。

問題のみのページはコチラ

問題で使うファイル等

GitHubにあります。ファイルは

https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.26

にあります。

クローンは以下のようにお願いします。

$ git clone https://github.com/ryuichiueda/ShellGeiData.git

環境

シェル芸を行うのはUbuntu Linux 16.04です。確認はMacのExcelやWord, PowerPointで行いました。今回は特にワンライナーにこだわる必要はありません。シェルスクリプトにしても構いません。もちろん、一般解にこだわる必要もありません。

イントロ

第26回シェル芸勉強会及びエクシェル芸勉強会

Q1

.xlsxや.docx、.pptxファイルはzipファイルです。リポジトリの中のxlsx,docx,pptxを展開し、中にどんなファイルがあるか見て、再び戻して再び.xlsx,.docx,.pptxファイルとして開いてみてください。

解答

解凍すると、一つのディレクトリに収まってなく、その場にいくつかのファイルが展開されるので厄介です。ファイルの置き場所と展開する場所を分けましょう。

$ mkdir ~/tmp
   $ cd ~/tmp
   ###tmpの下に置かずに解凍###
   $ unzip ~/ShellGeiData/vol.26/graph.xlsx 
   ueda@remote:~/tmp$ ls
   [Content_Types].xml _rels docProps xl
   ueda@remote:~/tmp$ tree
   .
   ├── [Content_Types].xml
   ├── _rels
   ├── docProps
   │   ├── app.xml
   │   ├── core.xml
   │   └── thumbnail.jpeg
   └── xl
    ├── _rels
    │   └── workbook.xml.rels
    ├── calcChain.xml
    ├── charts
    │   └── chart1.xml
    ├── drawings
    │   ├── _rels
    │   │   └── drawing1.xml.rels
    │   └── drawing1.xml
    ├── styles.xml
    ├── theme
    │   └── theme1.xml
    ├── workbook.xml
    └── worksheets
    ├── _rels
    │   └── sheet1.xml.rels
    └── sheet1.xml
   
   10 directories, 14 files
   ###再圧縮したファイルも別のディレクトリに作ると事故が少ない###
   ueda@remote:~/tmp$ zip -r ../hoge.xlsx ./

Q2

20141019OSC_LT.pptxのスライドに何回「危険」という単語が出てくるか数えてください。画像になっているものは除きます。

解答

$ unzip ~/ShellGeiData/vol.26/20141019OSC_LT.pptx ;
   grep -o 危険 ppt/slides/slide* | wc -l
   17

unzipは-pオプションで必要なファイルだけcatすることができます。ということで次のようにすると完全にワンライナーになります。

$ unzip -p ~/ShellGeiData/vol.26/20141019OSC_LT.pptx 'ppt/slides/slide*' |
    grep -o 危険 | wc -l
   17

Q3

20141019OSC_LT.pptxのスライドから画像を抽出して、一つのディレクトリにまとめてzipで固めてください。

解答

$ unzip ~/ShellGeiData/vol.26/20141019OSC_LT.pptx ;
    zip -r media.zip ./ppt/media/

Q4

20141019OSC_LT.pptxのスライドの7ページ目のテキストをスクレイピングしましょう。以下が出力の例です。

戦果(?)
   初日だけで見知らぬ方のマシン3台轟沈
   その他自爆者多数
   Docker上で試したらホストマシン沈黙の報告
   自分の本がサイト経由で1冊だけ売れた
   フォロワーが1人減った
   (以下、フッタ等の文字列が混ざっても可とします)

解答

$ unzip -p ~/ShellGeiData/vol.26/20141019OSC_LT.pptx ppt/slides/slide7.xml |
    xmllint --format - | grep '<a:[pt]>' | sed 's;</.*;;' |
    sed 's;<.*>;;' | awk 'NF==0{print "@@@"}{print}' |
    xargs | sed 's/@@*/\\n/g' | awk 'NF' | tr -d ' '
   戦果(?)
   初日だけで見知らぬ方のマシン3台轟沈
   その他自爆者多数
   Docker上で試したらホストマシン沈黙の報告
   自分の本がサイト経由で1冊だけ売れた
   フォロワーが1人減った
   2014/10/19
   OSCTokyo/Fall2014
   7

Q5

graph.xlsxの2列の数字を抜き出して端末にSSV形式のデータ(CSVのカンマがスペースになったもの)、あるいはセルの番号と値のリストとして抜き出してください。

解答

###スペース区切り###
   $ unzip ~/ShellGeiData/vol.26/graph.xlsx;
    cat xl/worksheets/sheet1.xml |
    sed 's;</row>;\\n;g' | sed 's;</v>.*<v>; ;' |
    sed 's;.*<v>;;' | sed 's;</v>.*;;' | grep -v "^<"
   ###スペース区切り・ワンライナーバージョン###
   $ unzip -p ~/ShellGeiData/vol.26/graph.xlsx xl/worksheets/sheet1.xml |
    sed 's;</row>;\\n;g' | sed 's;</v>.*<v>; ;' |
    sed 's;.*<v>;;' | sed 's;</v>.*;;' | grep -v "^<"

もっとスマートに行うには、html-xml-utilsとlibxml2-utilsをインストールしてhxselectコマンドやxmllintを使います。

$ sudo apt install html-xml-utils
   $ sudo apt install libxml2-utils
   ###番号と値のリスト###
   $ unzip -p ~/ShellGeiData/vol.26/graph.xlsx xl/worksheets/sheet1.xml |
    hxselect c -s '\\n' | sed 's;[^=]*=";;' |
    sed 's;".*<v>; ;' | sed 's;<.*;;'
   $ unzip -p ~/ShellGeiData/vol.26/graph.xlsx xl/worksheets/sheet1.xml |
    xmllint --format - | grep -e '<c r=' -e '<v>' | xargs |
    sed 's;</v>;\\n;g' | sed 's/.*=//' | sed 's/>.*>/ /'

もっと便利なツールもあるという噂ですが、とりあえず私からこれくらいで・・・

Q6

hanshin.xlsxのシートについてQ2と同様SSV形式か、セルの番号と値のリストとして端末上に出力してください。日付のセルについては何を出力しても良いことにします。

解答

文字列は展開したファイルのxl/sharedStrings.xmlに順番に入っています。

$ unzip ~/GIT/ShellGeiData/vol.26/hanshin.xlsx 
   $ xmllint --format xl/sharedStrings.xml | head
   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="18" uniqueCount="15">
    <si>
    <t>真弓</t>
    <rPh sb="0" eb="2">
    <t>マユミ</t>
    </rPh>
    <phoneticPr fontId="1"/>
    </si>
    <si>

読みのデータが邪魔なので、消去した上でリストを作っておきます。

$ unzip -p ~/GIT/ShellGeiData/vol.26/hanshin.xlsx xl/sharedStrings.xml |
    hxselect si -s '\\n' | awk -F'[<>]' '{print NR-1,$5}' > strings
   $ head -n 3 strings 
   0 真弓
   1 弘田
   2 バース

次に、シートのデータを加工していきます。文字列のセルには「t="s"」という属性があるので、これで文字列のセルと数字のセルを分けます。文字列のセルのv要素にある数字は、sharedStrings.xmlの何番目の文字列がこのセルに入るかを意味します。(sharedStrings.xmlはXMLファイルなのにデータの並び順で文字列を管理しているという・・・)

$ unzip -p ~/GIT/ShellGeiData/vol.26/hanshin.xlsx xl/worksheets/sheet1.xml |
    hxselect c -s '\\n' | grep '<v>' |
    awk -F'[<> "]' '/t="s"/{print $4,"s",$(NF-4)}!/t="s"/{print $4,"n",$(NF-4)}'
   B1 n 42522
   C1 n 42561
   A2 n 1
   B2 s 0
   C2 s 0
   A3 n 2
   B3 s 1
   C3 s 9
   A4 n 3
   B4 s 2
   ...

ここまでできたら、awkで無理やり文字列のファイルとデータのファイルを混ぜて答えを出します。この例ではFILENAMEという変数を使っています。

$ unzip -p ~/GIT/ShellGeiData/vol.26/hanshin.xlsx xl/worksheets/sheet1.xml |
    hxselect c -s '\\n' | grep '<v>' |
    awk -F'[<> "]' '/t="s"/{print $4,"s",$(NF-4)}!/t="s"/{print $4,"n",$(NF-4)}' |
    awk 'FILENAME=="strings"{s[$1]=$2}FILENAME=="-"&&
   $2=="s"{print $1,s[$3]}$2=="n"{print $1,$3}' strings -
   B1 42522
   C1 42561
   A2 1
   B2 真弓
   C2 真弓
   A3 2
   B3 弘田
   C3 北村
   A4 3
   B4 バース
   C4 バース
   A5 4
   B5 掛布
   C5 掛布
   A6 5
   B6 岡田
   C6 佐野
   A7 6
   B7 佐野
   C7 木戸
   A8 7
   B8 平田
   C8 平田
   A9 8
   B9 木戸
   C9 永尾
   A10 9
   B10 ゲイル
   C10 池田

Q7

certificate.docxファイルを開いて確認し、人の名前が入るところに好きな名前を入れてみましょう。

解答

ホームの下にtmp等の一時ディレクトリを作ってそこで試しましょう。-iオプションは、BSD系のsedの場合-i.bakと言うように拡張子をつけてバックアップファイルを作らなければなりませんが、その場合はバックアップファイルを消してから再圧縮します。

###~/tmp/で作業すると仮定します###
   $ unzip ~/ShellGeiData/vol.26/certificate.docx ; 
   sed -i 's/WINNER/しぇる芸のオッサン/' word/document.xml ; 
   zip -r ../hoge.docx ./
   ###ワーニングが出ますが開けます###

Q8

Q7を応用し、次のリストlist.txtで、複数の表彰状を作ってみましょう。

$ cat list.txt 
   シェル芸おじさん
   シェル芸野郎
   変態シェル芸豚野郎

解答

unzipに-o(overwrite)オプションをつけると便利です。

$ cat ~/ShellGeiData/vol.26/list.txt | 
   while read name ; do unzip -o ~/ShellGeiData/vol.26/certificate.docx ;
    sed -i "s/WINNER/$name/" word/document.xml ;
    zip -r ../$name.docx ./ ; done
ノート   このエントリーをはてなブックマークに追加 
 

prev:【問題のみ】第26回シェル芸勉強会及びエクシェル芸勉強会 next:第26回シェル芸勉強会及びエクシェル芸勉強会

やり散らかし一覧

記事いろいろ