【問題と解答】jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会
Sat Nov 3 16:10:40 JST 2018 (modified: Sat Nov 3 16:10:40 JST 2018)
views: 2880, keywords:プログラミング,勉強会,シェル芸,シェル芸勉強会 この記事は最終更新日が6年以上前のものです。
- 問題で使われているデータファイルはGitHubにあります。クローンは以下のようにお願いします。
git clone https://github.com/ryuichiueda/ShellGeiData.git $
- 環境: 解答例はUbuntu Linux 18.04 で作成。Macの場合はcoreutilsをインストールすると、GNUのコマンドが使えます。BSD系の人は玄人なので各自対応のこと。
Q1
次のように、「jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会」からモヤモヤを除去してください。
echo 'jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会' | ...
jus共催 第38回シェル芸勉強会
解答例
$ echo 'jus共催 第38回҈҈҉҈҈҉シ҈҉ェ҈҉ル҈҉芸҈҉勉҈҉強҈҉会' | xxd -p | sed 's/d28[89]//g' | xxd -r -p
jus共催 第38回シェル芸勉強会
Q2
リポジトリの中の仏説摩訶般若波羅蜜多心経
(ぶっせつまかはんにゃはらみたしんぎょう)を使って、次のように、任意の文字列から、般若心経にある漢字だけを抽出してください。できない人で宗教上問題ない人は、般若心経を10000万回遍唱えてください。
echo 不摂生 | ...
不
生
解答例
$ echo 不摂生 | grep -o . | grep -f <(grep -o . 仏説摩訶般若波羅蜜多心経)
不
生
Q3
次の江戸時代の元号を順番に並び替えてください。ウェブから情報を取るときは何度もアクセスしないように一旦ファイルに落としましょう。
元禄
安政
元和
享保
解答例
$ curl 'https://ja.wikipedia.org/wiki/%E5%85%83%E5%8F%B7%E4%B8%80%E8%A6%A7_(%E6%97%A5%E6%9C%AC)' > a
$ cat a | sed -n '/<li>.*元和/,/<li>.*慶応/p' | grep -o '..</a><small>' |
sed 's/<.*//' | awk '{print NR,$1}' | cat - <(sed 's/^/@ /' edo ) |
sort -k2,2 | uniq -d -f 1 | sort -k1,1n | awk '{print $2}'
元和
元禄
享保
安政
Q4
エクセルの横の列のA, B, C, ..., Z, AA, AB, AC, ..., ZZ, AAA, AAB, ...の中の、XYZは何番目にあるでしょうか。Aを1番目とします。
解答例
$ echo {A..Z} {A..Z}{A..Z} {A..Z}{A..Z}{A..Z} | tr ' ' \\n | nl | grep XYZ
16900 XYZ
Q5
標準偏差10、平均値0のガウス分布に従う乱数を発生させてください。また、乱数のヒストグラムを描いてください。ヒストグラムは分布の形が分かれば適当で大丈夫です。
解答例
乱数生成は(近似ですが)次のようにできます。
$ cat /dev/urandom | tr -dc 0-9 | fold -b10 | sed 's/^/0./' |
awk '{a+=$1}NR%12==0{print (a-6)*10;a=0}'
ヒストグラムは、例えば次のように出してみましょう(ダメな例)。
###10万個生成###
$ cat /dev/urandom | tr -dc 0-9 | fold -b10 | sed 's/^/0./' |
awk '{a+=$1}NR%12==0{print (a-6)*10;a=0}' | head -n 100000 > a
###-0.xxxと0.xxxが共に0に丸められてしまうので、そこだけ頻度が倍になる###
$ awk '{print int($1)}' a | sort -n -k1,1 | uniq -c |
awk '{print $2,int($1/200)}' |
awk '{printf $1; for(i=1;i<=$2;i++)printf "*"; print ""}'
・・・
-10***********
-9************
-8**************
-7**************
-6****************
-5*****************
-4*****************
-3******************
-2******************
-1*******************
0****************************************
1********************
2******************
3******************
4*****************
5****************
6***************
7***************
8*************
・・・
一度、大きな数を足してから引くと回避できます。
$ awk '{print int(1000+$1)}' a | sort -n -k1,1 | uniq -c |
awk '{print $2-1000,int($1/200)}' |
awk '{printf("%d\t", $1); for(i=1;i<=$2;i++)printf "*"; print ""}' |
grep '\*'
-25 *
-24 *
-23 *
-22 *
-21 **
-20 ***
-19 ***
-18 ****
-17 *****
-16 ******
-15 *******
-14 ********
-13 *********
-12 **********
-11 ***********
-10 ************
-9 **************
-8 **************
-7 ****************
-6 *****************
-5 *****************
-4 ******************
-3 ******************
-2 *******************
-1 *******************
0 ********************
1 ********************
2 ******************
3 ******************
4 *****************
5 ****************
6 ***************
7 ***************
8 *************
9 ************
10 ************
11 **********
12 *********
13 ********
14 *******
15 *****
16 *****
17 ****
18 ***
19 ***
20 **
21 *
22 *
23 *
Q6
広済寺ホームページから、「妙法蓮華経(新字体、平成20年校正)」(https://www.kosaiji.org/download/kyoten/myoho_shinji.txt )のファイルをダウンロードして、仏説摩訶般若波羅蜜多心経
と漢字で4文字連続で一致している文字列を探してください。ギブアップかつ宗教上問題のない人は、妙法蓮華経を暗記していてください。
解答例
$ awk '{for(i=1;i<=length($0)-1;i++)print FILENAME, substr($0,i,4)}' \
<(tr -d \\n < 仏説摩訶般若波羅蜜多心経 ) \
<(nkf -wLux myoho_shinji.txt | tr -d \\n ) |
sort -k2,2 | uniq | uniq -f 1 -d | awk '{print $2}' | grep -v 。
阿耨多羅
眼耳鼻舌
究竟涅槃
三世諸仏
三藐三菩
耳鼻舌身
若波羅蜜
色声香味
声香味触
即説呪曰
多羅三藐
得阿耨多
般若波羅
鼻舌身意
亦復如是
羅三藐三
耨多羅三
藐三菩提
Q7
a^2 + b^2
がab + 1
で割り切れる正の整数の組合せa,b
を生成してください(ランダムで良いです)。また、このとき、(a^2+b^2)/(ab+1)
が正の整数の二乗になっていることを確かめてください。
解答例
$ cat /dev/urandom | tr -dc 0-9 | fold -b2 | sed 's/^0*//' |
xargs -n 2 | awk '($1*$1 + $2*$2)%($1*$2+1)==0{a=($1*$1 + $2*$2)/($1*$2+1);"factor " a |
getline x ; print $1,$2,x;fflush()}' |
awk '{for(i=4;i<=NF;i++)a[$i]++;printf $1" "$2" "$3;x="OK";for(k in a){if(a[k]%2 == 1)x="NG"}print x}'
Q8
数列x_{i+1} = a * x_i * (1 - x_i)
について、x
の初期値を0.5としてAWKで出力して、百万回以上連続で、これまで出てきていない数字を出力してください。ただし、a
は3以上、4未満の小数から選んでください。これに飽き足らない人は限界に挑戦してください。
解答例
こうやって探しました。なかなか答えが出てこない場合には100,000桁に桁を落として候補を絞ってから検証する方法もあります。
cat /dev/urandom | tr -dc 0-9 | fold -b10 | sed 's/^/0./' |
awk '{print $1*4}' | awk '$1>=3' |
while read a ; do awk -v a=$a 'BEGIN{OFMT="%.20f";x=0.5;while(1){print x;x=a*x*(1-x)}}' |
head -n 1000000 | sort -u | wc -l | awk -v a=$a '$1==1000000{print a,$1}' ; done | head -n 1
3.90172 1000000