■USP友の会 勉強会 番外編(OSC 2013 Tokyo/Spring)を解いてみた。
下記で番外編と、5~9までを解いてないと判明したようなので。。。
「第13回危険でない方のシェル芸勉強会」を解いてみた。
http://labunix.hateblo.jp/entry/20141005/1412439761
1.FizzBuzz(準備運動)
・こういう出力を得る
1,2,Fizz,4,Buzz
・短く書くこと。
■短く無い方法
$ seq 1 16 | awk '{if($1%15==0){print "FizzBuzz"} \
else{if($1%5==0) {print "Buzz"} \
else{if($1%3==0) {print "Fizz"} \
else{print $0}}}}' | xargs echo -n | sed s/" "/","/g
1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz,16
■短い方法
括弧「()」が無くても良いみたいだけど変な癖が付かない程度に。
$ seq 1 16 | awk '($1%3==0){print "Fizz"}($1%5==0){print "Buzz"}{print $1}' | \
tr '\n' ',';echo
1,2,Fizz,3,4,Buzz,5,Fizz,6,7,8,Fizz,9,Buzz,10,11,Fizz,12,13,14,Fizz,Buzz,15,16,
2.数を数える
■原稿って何?なので、bashのドキュメントから計測。
sedを挟むのは同じ行に複数のキーワードがある想定。
$ zcat /usr/share/doc/bash/*.gz | sed s/"[Dd]ebian"/"&\n"/g | grep Debian | wc -l
30
$ zcat /usr/share/doc/bash/*.gz | sed s/"[Dd]ebian"/"&\n"/g | grep [Dd]ebian | wc -l
235
■同じ行に複数キーワードがあることを考慮しないと。。。
$ zcat /usr/share/doc/bash/*.gz | grep [Dd]ebian | wc -l
226
3.データ抽出
・キーa,bそれぞれについて、一番大きい数字を取り出してください。
$ cat hoge
a 32
b 335
a 12
b -3.21
b 31533
a -301
■「uniq -w 1」は面白いオプション。
$ for c in a b;do grep "^${c}" hoge | sort -nr -k 2 | head -1;done
a 32
b 31533
$ sort -nr -k 1 -k 2 hoge | uniq -w 1 | head -2
b 31533
a 32
4.日付の計算
・1978年2月16日は、
2013年2月23日の何日前でしょう?
$ echo $((`date -d "20130223" '+%s'` - `date -d "19780216" '+%s'`)) | awk '{print $1/(60*60*24)}'
12791
5.リストにないものを探す
・1から10までの数字のうち、numにないものは?
$ cat num
7
6
4
2
10
1
$ seq 1 10 | cat - num | sort | uniq -c | awk '($1==1){print $2}'
3
5
8
9
6.エクセルの読み書き
■Tsukubaiのビジネス版のネタのようですので、
debianで扱えるように変更。
$ sudo apt-get install -y python-openpyxl
$ cat sample_xlsx.py
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
wb = Workbook()
dest_filename = r'Excel2007_from_debian.xlsx'
ws = wb.worksheets[0]
ws.title = u"Unicode_日本語版"
ws.cell('A1').value = '項番'
ws.cell('A2').value = 1
ws.cell('A3').value = 2
ws.cell('A4').value = 3
ws.cell('A5').value = 4
ws.cell('B1').value = 'サンプル'
ws.cell('B2').value = '一'
ws.cell('B3').value = '二'
ws.cell('B4').value = '三'
ws.cell('B5').value = '四'
wb.save(filename = dest_filename)
$ python sample_xlsx.py
■上記で書いたものはLibreOfficeでも開ける。
$ libreoffice Excel2007_from_debian.xlsx
■コンソールで読みたい人向け
$ sudo apt-get install -y gnumeric
$ ssconvert Excel2007_from_debian.xlsx Excel2007_from_debian.csv
Using exporter Gnumeric_stf:stf_csv
$ cat Excel2007_from_debian.csv
項番,サンプル
1,一
2,二
3,三
4,四
■csvならということで余談。
年間カレンダーのcalとbash。CSV出力する。
http://labunix.hateblo.jp/entry/20140120/1390148410
$ for y in `seq 1 12`;do \
MYCAL="2014/${y}/01"; \
echo -e "\n$MYCAL,,,,,," | sed s%"/01"%%; \
echo "日,月,火,水,木,金,土"; \
n=`date -d "${MYCAL}" '+%u'`; \
l=`date -d "${MYCAL} next month last day" '+%d'`; \
if [ $n -ne 7 ];then \
for s in `seq 1 $n`;do echo -n "0 ";done; \
else \
echo " "; \
fi | \
for d in `xargs` `seq 1 $l`;do \
echo "$d $n" | \
awk '{if(($1+$2)%7==0) printf "%3d\n",$1%32;else printf "%3d",$1%32}'; \
done | sed s/" *\([0-9]*\)"/"\1,"/g | sed s/"^,"//g | sed s/",\$"//g | \
sed s/"^,,"//g | sed s/"^0,"/","/g | sed s/",0"/","/g; \
echo;unset n m MYCAL; \
done > cal.csv
$ ssconvert --export-type=Gnumeric_Excel:xlsx cal.csv cal.xlsx
$ libreoffice cal.xlsx
■何も変更せずにxlsxからcsvにするとxlsxで見たと通りに年の表記がおかしくなる。
$ cat export_cal.csv | head -5
41640,,,,,,
日,月,火,水,木,金,土
,,,1,2,3,4
5,6,7,8,9,10,11
12,13,14,15,16,17,18
■年を書式設定で「YYYY/M」にすると「未定義の数の書式ID」が出るが問題ない。
また、非表示の日が「/01」として出力される。
$ ssconvert cal.xlsx export_cal.csv
Using exporter Gnumeric_stf:stf_csv
未定義の数の書式ID '43'
未定義の数の書式ID '41'
未定義の数の書式ID '44'
未定義の数の書式ID '42'
Unexpected element 'workbookProtection' in state :
workbook
$ cat export_cal.csv
2014/01/01,,,,,,
日,月,火,水,木,金,土
,,,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,31,
,,,,,,
2014/02/01,,,,,,
日,月,火,水,木,金,土
,,,,,,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,
,,,,,,
2014/03/01,,,,,,
日,月,火,水,木,金,土
,,,,,,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,31,,,,,
,,,,,,
2014/04/01,,,,,,
日,月,火,水,木,金,土
,,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,,,
,,,,,,
2014/05/01,,,,,,
日,月,火,水,木,金,土
,,,,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,31
,,,,,,
,,,,,,
2014/06/01,,,,,,
日,月,火,水,木,金,土
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,,,,,
,,,,,,
2014/07/01,,,,,,
日,月,火,水,木,金,土
,,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,31,,
,,,,,,
2014/08/01,,,,,,
日,月,火,水,木,金,土
,,,,,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
31,,,,,,
,,,,,,
2014/09/01,,,,,,
日,月,火,水,木,金,土
,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,,,,
,,,,,,
2014/10/01,,,,,,
日,月,火,水,木,金,土
,,,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,31,
,,,,,,
2014/11/01,,,,,,
日,月,火,水,木,金,土
,,,,,,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,,,,,,
,,,,,,
2014/12/01,,,,,,
日,月,火,水,木,金,土
,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,31,,,
■ここでは「/01」は唯一なので、「sed s%/01,%,%g」にパイプすれば消せる。
$ cat export_cal.csv | sed s%/01,%,%g | grep ^2014
2014/01,,,,,,
2014/02,,,,,,
2014/03,,,,,,
2014/04,,,,,,
2014/05,,,,,,
2014/06,,,,,,
2014/07,,,,,,
2014/08,,,,,,
2014/09,,,,,,
2014/10,,,,,,
2014/11,,,,,,
2014/12,,,,,,
7.速いソート
1億行のデータのソート
■1億行のデータを作る方が大変。
ところでTSUKUBAIのビジネス版のmsortは実在するlinuxコマンドとは別物です。
$ time seq 1 100000000 > sample.log
real 1m48.962s
user 1m44.307s
sys 0m2.956s
$ du -h sample.log
849M sample.log
8.ソートして集計
■これもTSUKUBAIコマンド入りなので、普通に。。。
$ time awk '{sum+=$1};END{print sum}' sample.log
5000000050000000
real 1m3.529s
user 1m2.304s
sys 0m0.972s
■ガウスの等差数列の和の手法でごまかす。
$ time echo `handred_million=100000000;echo $((($handred_million/2)*($handred_million+1)))`
5000000050000000
real 0m0.002s
user 0m0.000s
sys 0m0.000s
9.足し算する(精度良く)
$ cat num
0.124332364364363
-112532.2335
325235
$ cat num | tr '\n' '+' | echo `xargs`0 | bc
212702.890832364364363
10.横に並んだ数字のソート
$ cat file
1 3153 131 31 41 9
31 0 3 245 123
3 42 53 1 19 4 124 1111
■一行づつ読み込んで行列入れ替え
$ while read line ;do \
echo $line | tr ' ' '\n' | sort -n | xargs echo -n ;echo; \
done <file
1 9 31 41 131 3153
0 3 31 123 245
1 3 4 19 42 53 124 1111