【問題と解答】第22回ゴールデンウィークの存在疑惑シェル芸勉強会

Pocket
LINEで送る

問題のみのページはこちら

イントロのプレゼン資料

ここです。

問題で使うファイル等

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

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

にあります。

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

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

環境

今回はUbuntu Linuxで解答例を作りましたので、BSD系、Macな方は以下の表をご参考に・・・。

Mac,BSD系 Linux
gdate date
gsed sed
tail -r tac
gtr tr
gfold fold

Q1

次のファイルの中身について、「cat <ファイル名>」から初めて、同じワンライナーでそれぞれ中央値を求めてください。データの数が偶数の場合は、中央の二つの値の平均を中央値とします。

ueda@remote:~/GIT/ShellGeiData/vol.22/Q1$ cat a
1
3
4
1
6
6
8
2
ueda@remote:~/GIT/ShellGeiData/vol.22/Q1$ cat b
3.4
13
4242
-4
-5

解答

データ数が偶数と奇数の時で場合分けが必要で面倒くさいです。(場合分けのない方法絶賛募集中。)

ueda@remote:~/GIT/ShellGeiData/vol.22/Q1$ cat a | sort -n |xargs |
awk 'NF%2==0{print 0.5*($(NF/2)+$(NF/2+1))}NF%2==1{print $(NF/2+1)}'
3.5
ueda@remote:~/GIT/ShellGeiData/vol.22/Q1$ cat b | sort -n | xargs |
awk 'NF%2==0{print 0.5*($(NF/2)+$(NF/2+1))}NF%2==1{print $(NF/2+1)}'
3.4

Q2

次のような出力から初めて、

ueda@remote:~$ echo カレーライス 醤油ラーメン | ...

次のような出力を得てください(表示がずれてますが、「ー」のところで文字列をクロスさせています)。最初のパイプより右側はマルチバイト文字を使わないようにしてみましょう。「ー」が何文字目にあるか等の情報は何でも使って結構です。

      カ
      レ
醤油ラーメン
      ラ
      イ
      ス

解答

ueda@remote:~$ echo カレーライス 醤油ラーメン |
 awk '{print $2;gsub(/./,"      &\n",$1);print $1}' |
 awk 'NR==1{a=$1}NR!=1{print $1==substr(a,4,1)?a:$0}'
      カ
      レ
醤油ラーメン
      ラ
      イ
      ス

Q3

次のデータについて、

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3
aaabbb
bababa
aaabbb
aaabbb
bababa
bbbbba

次のような出力を得てください。

bababa  2 5
aaabbb  1 3 4
bbbbba  6

次に、得られた答えから元のデータを復元してください。Q3の答えはQ3.ansにあります。

解答

前半はAWKの連想配列のおさらい問題でした。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3 |
awk '{a[$1]=a[$1]" "NR}END{for(k in a){print k,a[k]}}' 
bababa  2 5
aaabbb  1 3 4
bbbbba  6

復元は次の通り。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3.ans |
 awk '{for(i=2;i<=NF;i++)print $1,$i}' |
 sort -k2,2n | awk '{print $1}'
aaabbb
bababa
aaabbb
aaabbb
bababa
bbbbba

Q4

次のファイルについて、素数行目に存在するりんごとみかんをそれぞれ数えてください。できる人は素数の行を2,3,5,7と明示的に指定しないでやってみてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q4
りんご
りんご
みかん
みかん
りんご
みかん
りんご
りんご

解答

先にfactorを使ってからpasteでQ4ファイルをくっつけると楽です。

ueda@remote:~/GIT/ShellGeiData/vol.22$ seq 1 100 | factor |
 paste - Q4 | awk 'NF==3' | grep -oE '[あ-ん]+' | sort | uniq -c
      1 みかん
      3 りんご

Q5

足して10になる並びを全て見つけてみましょう。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q5
1 3 4 4 2 3 5 6 7 9 1 4

解答

計算量的には損ですが、先に組み合わせを全部列挙すると楽です。ただ、列挙は面倒くさいです。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q5 |
 awk '{for(len=1;len<=NF;len++)for(shift=1;shift<=NF-len+1;shift++)
{for(i=shift;i<shift+len;i++){printf $i" "};print ""}}' |
 awk '{a=0;for(i=1;i<=NF;i++)a+=$i;print $0,a}' | awk '$NF==10'
9 1  10
4 4 2  10
2 3 5  10

Q6

次のファイルQ6_1のX,Y,Zに、

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_1 
所謂いわゆる「Z」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
YのからだにXでもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

Q6_2に書いてある文字列を当てはめてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_2
X 駄馬の首
Y 人間
Z 死相

解答

sedでsedのコマンドを作ってsedに食わせます。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_2 | sed 's;^;s/;' |
 tr ' ' '/' | sed 's;$;/;' | sed -f - Q6_1
所謂いわゆる「死相」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
人間のからだに駄馬の首でもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

Q7

明示的に端末を閉じたりシェルを終わらせるためのコマンド(shutdown, reboot, exit, logout等)以外で端末を閉じてみてください。

解答例

execで何かコマンドを指定すると、シェルのプロセスが終わって端末が閉じます。(他の方法があれば是非。)

ueda@remote:~$ exec echo アホ
アホ
Connection to test.usptomo.com closed.
uedamb:~ ueda$ 

Q8

次のC++のコードに関数プロトタイプをくっつけてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.cc 
#include <iostream>
#include <string>
using namespace std;

void aho(void)
{
	cout << nazo() << endl;
}

string nazo(void)
{
	return "謎";
}

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}

つまりこういう出力を作ります。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.ans.cc 
#include <iostream>
#include <string>
using namespace std;
void aho(void);
string nazo(void);

void aho(void)
{
	cout << nazo() << endl;
}

string nazo(void)
{
	return "謎";
}

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}

解答例

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.cc | grep ')$' |
 grep -v '^int main' | sed 's/$/;/' |
 awk 'BEGIN{a=0}FILENAME=="-"{a=1}{print a,$0}/using/{a+=2}' Q8.cc - |
 sort -s -k1,1 | sed 's/^..//'

Pocket{var j=d.createElement("script");j.id=i;j.src="https://widgets.getpocket.com/v1/j/btn.js?v=1";var w=d.getElementById(i);d.body.appendChild(j);}}(document,"pocket-btn-js");
LINEで送る

脚注   [ + ]

1. i+1)/2); if(x<(i+1)/2) print (v[x-1]+v[x])/2; else print v[x-1];}'

— Blacknon(エビス) (@blacknon_) 2016年4月30日

Q2

次のような出力から初めて、

ueda@remote:~$ echo カレーライス 醤油ラーメン | ...

次のような出力を得てください(表示がずれてますが、「ー」のところで文字列をクロスさせています)。最初のパイプより右側はマルチバイト文字を使わないようにしてみましょう。「ー」が何文字目にあるか等の情報は何でも使って結構です。

      カ
      レ
醤油ラーメン
      ラ
      イ
      ス

解答

ueda@remote:~$ echo カレーライス 醤油ラーメン |
 awk '{print $2;gsub(/./,"      &\n",$1);print $1}' |
 awk 'NR==1{a=$1}NR!=1{print $1==substr(a,4,1)?a:$0}'
      カ
      レ
醤油ラーメン
      ラ
      イ
      ス

Q3

次のデータについて、

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3
aaabbb
bababa
aaabbb
aaabbb
bababa
bbbbba

次のような出力を得てください。

bababa  2 5
aaabbb  1 3 4
bbbbba  6

次に、得られた答えから元のデータを復元してください。Q3の答えはQ3.ansにあります。

解答

前半はAWKの連想配列のおさらい問題でした。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3 |
awk '{a[$1]=a[$1]" "NR}END{for(k in a){print k,a[k]}}' 
bababa  2 5
aaabbb  1 3 4
bbbbba  6

復元は次の通り。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q3.ans |
 awk '{for(i=2;i<=NF;i++)print $1,$i}' |
 sort -k2,2n | awk '{print $1}'
aaabbb
bababa
aaabbb
aaabbb
bababa
bbbbba

Q4

次のファイルについて、素数行目に存在するりんごとみかんをそれぞれ数えてください。できる人は素数の行を2,3,5,7と明示的に指定しないでやってみてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q4
りんご
りんご
みかん
みかん
りんご
みかん
りんご
りんご

解答

先にfactorを使ってからpasteでQ4ファイルをくっつけると楽です。

ueda@remote:~/GIT/ShellGeiData/vol.22$ seq 1 100 | factor |
 paste - Q4 | awk 'NF==3' | grep -oE '[あ-ん]+' | sort | uniq -c
      1 みかん
      3 りんご

Q5

足して10になる並びを全て見つけてみましょう。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q5
1 3 4 4 2 3 5 6 7 9 1 4

解答

計算量的には損ですが、先に組み合わせを全部列挙すると楽です。ただ、列挙は面倒くさいです。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q5 |
 awk '{for(len=1;len<=NF;len++)for(shift=1;shift<=NF-len+1;shift++)
{for(i=shift;i<shift+len;i++){printf $i" "};print ""}}' |
 awk '{a=0;for(i=1;i<=NF;i++)a+=$i;print $0,a}' | awk '$NF==10'
9 1  10
4 4 2  10
2 3 5  10

Q6

次のファイルQ6_1のX,Y,Zに、

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_1 
所謂いわゆる「Z」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
YのからだにXでもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

Q6_2に書いてある文字列を当てはめてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_2
X 駄馬の首
Y 人間
Z 死相

解答

sedでsedのコマンドを作ってsedに食わせます。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q6_2 | sed 's;^;s/;' |
 tr ' ' '/' | sed 's;$;/;' | sed -f - Q6_1
所謂いわゆる「死相」というものにだって、
もっと何か表情なり印象なりがあるものだろうに、
人間のからだに駄馬の首でもくっつけたなら、
こんな感じのものになるであろうか、
とにかく、どこという事なく、見る者をして、
ぞっとさせ、いやな気持にさせるのだ。
私はこれまで、こんな不思議な男の顔を見た事が、
やはり、いちども無かった。

Q7

明示的に端末を閉じたりシェルを終わらせるためのコマンド(shutdown, reboot, exit, logout等)以外で端末を閉じてみてください。

解答例

execで何かコマンドを指定すると、シェルのプロセスが終わって端末が閉じます。(他の方法があれば是非。)

ueda@remote:~$ exec echo アホ
アホ
Connection to test.usptomo.com closed.
uedamb:~ ueda$ 

Q8

次のC++のコードに関数プロトタイプをくっつけてください。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.cc 
#include <iostream>
#include <string>
using namespace std;

void aho(void)
{
	cout << nazo() << endl;
}

string nazo(void)
{
	return "謎";
}

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}

つまりこういう出力を作ります。

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.ans.cc 
#include <iostream>
#include <string>
using namespace std;
void aho(void);
string nazo(void);

void aho(void)
{
	cout << nazo() << endl;
}

string nazo(void)
{
	return "謎";
}

int main(int argc, char const* argv[])
{
	aho();
	return 0;
}

解答例

ueda@remote:~/GIT/ShellGeiData/vol.22$ cat Q8.cc | grep ')$' |
 grep -v '^int main' | sed 's/$/;/' |
 awk 'BEGIN{a=0}FILENAME=="-"{a=1}{print a,$0}/using/{a+=2}' Q8.cc - |
 sort -s -k1,1 | sed 's/^..//'

Pocket

「【問題と解答】第22回ゴールデンウィークの存在疑惑シェル芸勉強会」への1件のフィードバック

コメントは停止中です。