第21回シェル芸勉強会 大阪サテライトに参加しました。

第21回シェル芸勉強会に大阪サテライト会場から参加しました。

【問題のみ】第21回未経験者大歓迎!誰でも働けるアットホームな職場ですシェル芸勉強会 – 上田ブログ

自分の解答を記載します。

A1

PDF からテキストを抽出するお題。

popplerパッケージに付いてくるpdftotextを使う。
https://www.archlinux.org/packages/extra/i686/poppler/files/

$ pdftotext bba.pdf - 2> /dev/null 
群馬のシャブばばあ

hoge.txt[2016/02/09 22:30:32]

A2

SJIS で1行のデータを UTF-8 で定数文字折り返しデータに変換する。

sedはマルチバイト対応なので折りたたむことができる。

cat anydata.cp932 | iconv -f SJIS | sed -E 's/.{35}/&\n/g'

SJIS が固定バイトであることを使って、先にfoldしてから文字コード変換すればよかった模様。

A3

2016年の日曜日を全て列挙する。

dateを使うのが正攻法だと思ったから、別の手法を考えた。
calはカレンダーを出力するコマンド。
引数を与えると(cal 〈day〉 〈month〉 〈year〉)表示する月を変更できる。

$ cal 1 4 2016
     April 2016     
Su Mo Tu We Th Fr Sa
                1  2 
 3  4  5  6  7  8  9 
10 11 12 13 14 15 16 
17 18 19 20 21 22 23 
24 25 26 27 28 29 30 
                     

解答

$ echo {1..12} | xargs -n 1 | xargs -I% cal 1 % 2016 | grep '^.[^[:space:]]' | awk 'START{i=0}$1=="Su"{i++}$1!="Su"{printf ("2016%02d%02d\n",i,$1)}' | wc # 解答省略用 wc
     52      52     468

A4

タグのついたデータを、新しいデータで更新する。

タグをキーとする連想配列を上書きするという発想しか出てこなかった。
連想配列といえばawkである。

$ cat data newdata | awk '{a[$1]=$2}END{for(v in a){print v,a[v]}}'
002 *******
003 群馬のシャブばばあ
004 尾崎んちのババア
005 純愛ババア学園
001 あみだばばあ

A5

スクリプトデバッグする。

a.bash

午前中に学んだodコマンドでバイナリを眺める。

$ cat a.bash | od -bcx
0000000 357 273 277 043 041 057 142 151 156 057 142 141 163 150 012 012
        357 273 277   #   !   /   b   i   n   /   b   a   s   h  \n  \n
           bbef    23bf    2f21    6962    2f6e    6162    6873    0a0a
0000020 145 143 150 157 040 110 145 154 154 012
          e   c   h   o       H   e   l   l  \n
           6365    6f68    4820    6c65    0a6c
0000032

先頭に3バイトと言えばBOM(Byte Order Mark)である。
BOM を消しつつ(trで制御文字を消して)実行。

$ cat a.bash | tr -cd '[[:print:]][[:space:]]' | sh
Hell

b.bash

odコマンd(ry

$ cat b.bash | od -bcx
0000000 043 041 057 142 151 156 057 142 141 163 150 012 012 154 163 040
          #   !   /   b   i   n   /   b   a   s   h  \n  \n   l   s    
           2123    622f    6e69    622f    7361    0a68    6c0a    2073
0000020 313 234 057 012
        313 234   /  \n
           9ccb    0a2f
0000024

チルダの文字コードが明らかにおかしい。
これまた午前中に知ったbashエスケープ展開で消して置換する。

$ cat b.bash | tr -d $'\x9c' | tr $'\xcb' '~' 
#!/bin/bash

ls ~/

A6

拡張正規表現正規表現で基本正規表現に変換する。
x+xx*に、{x}を展開する課題。

前からsedで全部置換する。
繰り返しはsedではできないので、コマンドを作ってシェルに投げる。

$ cat extended | sed -E 's/(\[.*\]|.)\+/\1\1*/g' | sed -E 's/\((.*)\)\{(.*)\}/`yes \1 | head -\2 | tr -d " \\n"`/g' | sed -E 's/(.)\{(.*)\}/`yes \1 | head -\2 | tr -d " \\n"`/g' | sed 's/^/echo /' | bash
aa*hhhhhhohohohohohohohohoho[0-9][0-9]*

Perl すごい↓


A7

各段落の文字数を数える。

全角スペースが段落の開始(区切り)になっていて改行は無視して大丈夫らしいので、まず改行を消して段落ごとに分けて数えた。

$ cat text | tr -d '\n' | sed 's/ /\n/g' | awk '$0=length($0)'
15
353
103

改行文字を消さないで数えるバージョン。

$ cat text | awk '/^ /{l=0}{print $0,l+=length($0)}END{print " "}' | grep -B 1 ' ' |tr '\n' ' '|sed 's/[0-9]\+ --//g'|grep -o '[0-9]*'
16
354
104

A8

メールの添付ファイルを引っこ抜く。

lessでだらーっと見てるとContent-Type: image/jpeg; name="CHINJYU.JPG"っていうそれっぽいのが目に入る。
grepしてみるとそれっぽいのがふたつあった。

$ grep Content-Type 1350369599.Vfc03I4682c8M940114.remote 
Content-Type: multipart/mixed; boundary=047d7b621ee6cf83c604cc276bb3
Content-Type: text/plain; charset=ISO-2022-JP
Content-Type: image/jpeg; name="CHINJYU.JPG"
Content-Type: image/jpeg; name="IMG_0965.JPG"

Content-Typeのちょっと下に明らかにエンコーディングされてるデータがあったから、抜き出してデコードして見たら見えた。

$ cat 1350369599.Vfc03I4682c8M940114.remote | sed '0,/Content-Type: image\/jpeg; name="CHINJYU.JPG"/d' | sed '0,/^$/d' | sed '/^--/,$d' | base64 -d > a.jpg

おまけの環境情報

$ bash --version | grep '[0-9]\.[0-9]'
GNU bash, version 4.3.42(1)-release (x86_64-unknown-linux-gnu)
$ uname -a
Linux host 4.4.1-2-ARCH #1 SMP PREEMPT Wed Feb 3 13:12:33 UTC 2016 x86_64 GNU/Linux
$ sed --version | grep '[0-9]\.[0-9]'
sed (GNU sed) 4.2.2
$ awk --version | grep '[0-9]\.[0-9]'
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.3-p5, GNU MP 6.1.0)
$ grep --version | grep '[0-9]\.[0-9]'
grep (GNU grep) 2.22
$ yaourt -Si coreutils | grep 'Version' # tr, ls, cat とか
Version         : 8.25-1
$ less --version | grep 'less [0-9]'
less 481 (PCRE regular expressions)
$ iconv --version | grep '[0-9]\.[0-9]'
iconv (GNU libc) 2.22
$ xargs --version | grep '[0-9]\.[0-9]'
xargs (GNU findutils) 4.4.2
$ cal --version | grep '[0-9]\.[0-9]'
cal from util-linux 2.27.1