今回は関西から、Twitter参加しました。
模範解答は上記の上田さんのブログの方にあるので、ここでは自分の出した変な回答の解説などを……
Q1. 次のように、画面にバッテンを描いてください。(この出力例の大きさは21×21です。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
x x
x x
x x
x x
x x
x x
x x
x x
x x
x x
x
x x
x x
x x
x x
x x
x x
x x
x x
x x
x x
|
https://twitter.com/kunst1080/status/495441002060980224
https://twitter.com/kunst1080/status/495458118512283649
考え方は以下のようにしました
- 空白を0、Xを1として数列を作成する
- できあがった数列を文字列置換する
まず前半
```
$ (jot 9|sort -rn;echo 0;jot 9)
9
8
7
6
5
4
3
2
1
0
1
2
3
4
5
6
7
8
9
```
9〜0〜9の数列を作成しています。あとでまとめてパイプに渡したいため、両端をカッコでくくっています。
数列を出力するために、FreeBSDなのでjotコマンドを使用していますが、Linux系の人はseqコマンドが使えると思います。どちらもなかったらyesとawkでがんばる感じですかね。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ (jot 9|sort -rn;echo 0;jot 9) | awk '{printf "%010d\n", 10^$1}'
1000000000
0100000000
0010000000
0001000000
0000100000
0000010000
0000001000
0000000100
0000000010
0000000001
0000000010
0000000100
0000001000
0000010000
0000100000
0001000000
0010000000
0100000000
1000000000
|
さっきの数列に対して、10のN乗を計算しています。また、awkのprintf関数で左ゼロ埋めをしています。
「X」の左側に見えてきましたね・・・
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ (jot 9|sort -rn;echo 0;jot 9) | awk '{printf "%010d\n", 10^$1}' | xargs -I% echo "echo -n %;echo % | rev"
echo -n 1000000000;echo 1000000000 | rev
echo -n 0100000000;echo 0100000000 | rev
echo -n 0010000000;echo 0010000000 | rev
echo -n 0001000000;echo 0001000000 | rev
echo -n 0000100000;echo 0000100000 | rev
echo -n 0000010000;echo 0000010000 | rev
echo -n 0000001000;echo 0000001000 | rev
echo -n 0000000100;echo 0000000100 | rev
echo -n 0000000010;echo 0000000010 | rev
echo -n 0000000001;echo 0000000001 | rev
echo -n 0000000010;echo 0000000010 | rev
echo -n 0000000100;echo 0000000100 | rev
echo -n 0000001000;echo 0000001000 | rev
echo -n 0000010000;echo 0000010000 | rev
echo -n 0000100000;echo 0000100000 | rev
echo -n 0001000000;echo 0001000000 | rev
echo -n 0010000000;echo 0010000000 | rev
echo -n 0100000000;echo 0100000000 | rev
echo -n 1000000000;echo 1000000000 | rev
|
「さっき作った文字列をrevコマンドで左右反転してくっつけるコマンド」をまず作成しています。paste使ってもよさそうですが…
echo -n は、改行せずにechoするためのオプションです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ (jot 9|sort -rn;echo 0;jot 9) | awk '{printf "%010d\n", 10^$1}' | xargs -I% echo "echo -n %;echo % | rev" | sh
10000000000000000001
01000000000000000010
00100000000000000100
00010000000000001000
00001000000000010000
00000100000000100000
00000010000001000000
00000001000010000000
00000000100100000000
00000000011000000000
00000000100100000000
00000001000010000000
00000010000001000000
00000100000000100000
00001000000000010000
00010000000000001000
00100000000000000100
01000000000000000010
10000000000000000001
|
作成したコマンドをshコマンドに食わせて実行しました。どう見てもXになっています。
あとは、1→X、0→スペース の変換をするだけです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ (jot 9|sort -rn;echo 0;jot 9) | awk '{printf "%010d\n", 10^$1}' | xargs -I% echo "echo -n %;echo % | rev" | sh | tr '01' ' X'
X X
X X
X X
X X
X X
X X
X X
X X
X X
XX
X X
X X
X X
X X
X X
X X
X X
X X
X X
|
……なんだか少しお題とは少し違う形をしてますが。。。trコマンドを使って文字の置換をしました。
1
|
tr '01' ' X'
|
で、'0'を' 'に、'1'が'X'に、まとめて置換できます。
こんな風に、sedを使わなくてもtrコマンドでも置換ができます。
Q4. 北から順(正確には都道府県番号順)に並べてください。
1
2
3
4
5
|
$ cat pref
鹿児島県
青森県
大阪府
群馬県
|
https://twitter.com/kunst1080/status/495454679942168576
https://twitter.com/kunst1080/status/495455438087794688
WEBの情報を活用して作業をする、という観点の問題でした。
頭を固くせず、使えるものは使いましょうっていうことですね。curlで取ってきた段階だと文字コードがSJISなので、nkf -w でUTF-8に変換します。
1
2
3
4
5
6
7
8
9
10
11
12
|
$ curl elze.tanosii.net/d/kenmei.htm -s | nkf -w
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>県番号,都道府県名,県庁所在地一覧</TITLE>
</HEAD>
<BODY>
(以下略
```charset=Shift_JISと書いてあり、元々Shift JISだったと思われますが、nkfでUTF-8になりコンソールで見えるようになっています。で、これにgrepしてほしいデータの行だけを抽出します。ここで
|
grep -of
1
2
3
4
5
6
7
8
|
を使うとスマートにできます。(@TSB_KZKさんに教えていただきました。)<br/>
manによると
<ul>
<li>-o, --only-matching…マッチした行の、マッチした部分だけを出力</li>
<li>-f FILE, --file=FILE…検索パターンをファイルから読み込む</li>
</ul>ということです。繋げると、
|
$ curl elze.tanosii.net/d/kenmei.htm -s | nkf -w | grep -of pref
青森県
群馬県
大阪府
鹿児島県
1
2
3
4
5
6
7
|
<br/>
### Q5. 各行の数字を大きい順にソートしてください。
|
$ cat input
A 31 1234 -42 4
B 10 31.1 -34 94
1
2
3
4
5
6
7
8
9
10
|
<a href="https://twitter.com/kunst1080/status/495463901664784384">https://twitter.com/kunst1080/status/495463901664784384</a><br/>
なんぞこれ……<br/>
考え方は以下のようにしました
<ul>
<li>1列目の名前で1行のデータを持つ中間ファイルを作成する</li>
<li>それぞれの中間ファイルをソートしてからくっつける</li>
</ul><br/>
まずはこのawkの塊ですが、最後のshを外すとこうなります。
|
$ awk '{for(i=2;i<NF;i++){f[NR]=$1;print “echo”,$i"»"$1}}END{for(i=1;i<NR+1;i++){print”(echo”,f[i],";sort -n”,f[i]")|xargs”}}' input
echo 31»A
echo 1234»A
echo -42»A
echo 10»B
echo 31.1»B
echo -34»B
(echo A ;sort -n A)|xargs
(echo B ;sort -n B)|xargs
$ awk '{for(i=2;i<NF;i++){f[NR]=$1;print “echo”,$i"»"$1}}' input
echo 31»A
echo 1234»A
echo -42»A
echo 10»B
echo 31.1»B
echo -34»B
1
2
3
|
「2列目以降の内容を、1列目の名前のファイルに出力するコマンド」が並びます。<br/>
またこのとき、連想配列「f[]」に、「A」と「B」(1列目の値)を退避しています。これはEND句で使用します。END句も合わせると
|
$ awk '{for(i=2;i<NF;i++){f[NR]=$1;print “echo”,$i"»"$1}}END{for(i=1;i<NR+1;i++){print”(echo”,f[i],";sort -n”,f[i]")|xargs”}}' input
echo 31»A
echo 1234»A
echo -42»A
echo 10»B
echo 31.1»B
echo -34»B
(echo A ;sort -n A)|xargs
(echo B ;sort -n B)|xargs
1
2
3
|
となり、「2列目以降の内容を、1列目の名前のファイルに出力するコマンド」と、「1列目の名前のファイルをソートしてxargsで横にするコマンド」が出来上がります。<br/>
(sort -n は数字としてソートするオプション)最後に、作成したコマンドをshコマンドに流しこんで実行します
|
$ awk '{for(i=2;i<NF;i++){f[NR]=$1;print “echo”,$i"»"$1}}END{for(i=1;i<NR+1;i++){print”(echo”,f[i],";sort -n”,f[i]")|xargs”}}' input | sh
A -42 31 1234
B -34 10 31.1
1
2
3
4
5
6
7
|
<br/>
### Q7. Q6のグラフを次のように縦にしてください。(多少ズレてもよしとします。)
|
*
*
*
*
*
5 3 4 10 2
$ cat num
5
3
4
10
2
1
2
3
4
5
6
7
8
9
10
|
<a href="https://twitter.com/kunst1080/status/495469327311593472">https://twitter.com/kunst1080/status/495469327311593472</a><br/>
※pasteコマンドを使いたかったので、この問題はLinux(ZorinOS)で解きました。<br/>
考え方は以下のようにしました
<ul>
<li>1列ずつ出力を作成する(プロセス置換(?)として作成)</li>
<li>それらをpasteで横に並べる</li>
</ul><br/>
まず前半、xargsの手前まで
|
$ cat num |xargs -I% echo “<(yes \"*\" | head -%;echo %)”
<(yes "*" | head -5;echo 5)
<(yes "*" | head -3;echo 3)
<(yes "*" | head -4;echo 4)
<(yes "*" | head -10;echo 10)
<(yes "*" | head -2;echo 2)
1
|
試しに1行目のコマンドだけを実行してみるとこんな感じです
|
$ yes “*” | head -5;echo 5
*
*
*
*
*
5
$ cat num |xargs -I% echo “<(yes \"*\" | head -%;echo %)” | xargs
<(yes “” | head -5;echo 5) <(yes “” | head -3;echo 3) <(yes “” | head -4;echo 4) <(yes “” | head -10;echo 10) <(yes “*” | head -2;echo 2)
1
2
3
|
並びましたね。<br/>
pasteコマンドに突っ込みたいので、echoで先頭にpasteを付けます。
|
$ cat num |xargs -I% echo “<(yes \"*\" | head -%;echo %)” | xargs echo paste
paste <(yes “” | head -5;echo 5) <(yes “” | head -3;echo 3) <(yes “” | head -4;echo 4) <(yes “” | head -10;echo 10) <(yes “*” | head -2;echo 2)
1
2
|
これで、「『棒グラフを1本ずつ生成するプロセス置換』を横に結合するコマンド」が出来上がりました。プロセス置換はbashの機能なので、shではなくbashに流し込みます
|
$ cat num |xargs -I% echo “<(yes \"*\" | head -%;echo %)” | xargs echo paste | bash
5 *
*
*
*
*
10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
若干変な出力ですが。。。<br/>
<br/>
以上です。<br/>
(なんだか今回まともにできてない気がしなくもないですが……)<br/>
<br/>
今回のシェル芸会で、だんだんとpasteコマンドの使用に慣れてきたような感じです。<br/>
便利そうなので、もっと手に馴染ませていきたいところ。<br/>
<br/>
<br/>
### 次回予告
次回は、大阪で有志を募ってサテライト会場やるかも???
|