全力で怠けたい

怠けるために全力を尽くしたいブログ。

シェル力が圧倒的に足りてないのでシェル力を養うために第12回シェル芸勉強会の問題に挑戦してみた。

シェル力が圧倒的に足りてないのでシェル力を養うために第12回シェル芸勉強会の問題に挑戦してみた。

問題はすごく工夫してあってパズル感覚で解けて楽しいしシェル力を養うのにも役立ちそう。

自分が使ってる zsh のバージョン。

$ zsh --version
zsh 5.8 (x86_64-apple-darwin19.6.0)

はじめに

自分はシェル力が圧倒的に足りてないので勉強のためにシェル芸勉強会の問題に挑戦してみた。

一応自分がシェルを使う用途を書いておくと普段の仕事は Mac を使ってやっててちょっとしたことをやるのにちょろっとシェルを使う程度。

ちなみにシェル芸ってなに? ってところは WikipediaUSP 友の会 から引用しておく。

シェル芸とは、主にUNIXオペレーティングシステムにおいて「マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理を CLI端末へのコマンド入力一撃で終わらせること」(USP友の会会長・上田隆一による定義[9])である。この技術を持つ人物を指すシェル芸人という呼び方も存在する[10]。

古典的には、UNIX系OSの各種CUIシェル上で単一または複数のコマンドを一行のコマンドラインでをつなぎ合わせて処理をおこなう、いわゆる「ワンライナー」系の手順にあたる。

第12回シェル芸勉強会の問題に挑戦してみた

少し前に第10回シェル芸勉強会の問題に挑戦してみたので今回は2つあとの 第12回シェル芸勉強会 の問題に挑戦してみた。 実は第10回シェル芸勉強会のあとは第11回シェル芸勉強会が開催しているようだけど、問題がスライドでしか公開してなくて入力データとかを転記するのが手間がかかりそうなのでやってない。

Q1

Question

次のように、画面にバッテンを描いてください。(この出力例の大きさは21x21です。)

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

Answer

大きさが決まってるのでベタに sed で特定行を編集してみた。

$ seq 21 | sed 's/.*/x x/' | sed '2,20 s/^/ /' | sed '11 s/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
x x

Q2

Question

小問1

次のechoの出力から回文を完成させてください。

ueda@remote:~$ echo たけやぶ
###このようにワンライナーで出力を作る###
ueda@remote:~$ echo たけやぶ | ...
たけやぶやけた

小問2

次のファイルの各行について回文を完成させてください。

ueda@remote:~/tmp$ cat kaibun 
たけやぶ
わたしまけ

Answer

小問1

awk で元の文字列を print してから元の文字列の長さ - 1から文字列の先頭まで逆順に print してみた。

$ echo たけやぶ | sed 's/./& /g' | awk '{printf $0}{for(i=NF-1;i>0;i--){printf $i}}' | tr -d ' '
たけやぶやけた

別解。awk だけでゴリゴリとやってみた。

$ echo たけやぶ | awk '{printf $0}{for(i=length-1;i>0;i--){printf substr($0, i, 1)}}'

小問2

小問1 のやつを while で回してみた。

$ cat kaibun | while read f; do echo $f | sed 's/./& /g' | awk '{printf $0}{for(i=NF-1;i>0;i--){printf $i}}' | tr -d ' '; echo ''; done;
たけやぶやけた
わたしまけましたわ

Q3

個人的には第11回シェル芸勉強会の問題のなかで一番難しかったかも。 南武線の駅名のリストをネットから探すのが大変だった。

Question

ウェブ等からデータを取得して南武線の駅名のリストを作ってください。

Answer

南武線の駅名のリストは Wikipedia を使わせてもらった。 sed で HTML をゴリゴリと編集してみた。

$ cat station | \
        grep '<td>' | \
        grep -oE 'title="([^駅"]+駅)"' | \
        sed -n '/川崎/,$p' | \
        sed -n '1,/立川/p' | \
        sed 's/title="//' | \
        sed 's/"//'
川崎駅
京急川崎駅
尻手駅
矢向駅
鹿島田駅
平間駅
向河原駅
武蔵小杉駅
武蔵中原駅
武蔵新城駅
武蔵溝ノ口駅
溝の口駅
津田山駅
久地駅
宿河原駅
登戸駅
中野島駅
稲田堤駅
京王稲田堤駅
矢野口駅
稲城長沼駅
南多摩駅
府中本町駅
分倍河原駅
西府駅
谷保駅
矢川駅
西国立駅
立川駅

Q4

こちらもネットからデータを持ってくるやつ。

Q3 よりは情報は見つけやすかったけどデータを HTML とか PDF で公開するの本当にやめてほしい。できれば JSON せめて XMLCSV で公開してほしい。

Question

北から順(正確には都道府県番号順)に並べてください。

ueda@remote:~/tmp$ cat pref 
鹿児島県
青森県
大阪府
群馬県

Answer

総務省CSV を公開してるのを使わせてもらった。CSV ファイル一つだけで総務省が好きになった。

総務省が公開してる CSV はこんな感じのフォーマットになってる。

ken-code,sityouson-code,tiiki-code,ken-name,sityouson-name1,sityouson-name2,sityouson-name3,yomigana
1,0,1000,北海道,,,,ほっかいどう
1,100,1100,北海道,札幌市,,,さっぽろし
1,101,1101,北海道,札幌市,,中央区,ちゅうおうく

総務省が公開してる CSV は文字エンコーディングShift_JIS なのが惜しいけど nkfUTF-8 に変換していろいろやってる。

$ curl -s https://www.soumu.go.jp/main_content/000608358.csv | \
        nkf -Sw | \
        grep -f pref | \
        awk -F, '{print $4}' | \
        uniq
青森県
群馬県
大阪府
鹿児島県

別解。国土交通省が公開してる やつ を使わせてもらった。

国土交通省が公開してるやつはこんな感じの HTML になってて機械にやさしくない作りになってる。 ちなみにタイトルは <title></title> になってて機械だけじゃなくて人間にもやさしくない。

  <tr> 
    <td>01</td><td>北海道</td>
  <td>25</td><td>滋賀県</td>
</tr>

sed でゴリゴリと編集してみた。

$ curl https://nlftp.mlit.go.jp/ksj/gml/codelist/PrefCd.html | \
        grep -f pref | \
        grep '<td>' | \
        sed -E 's@</?td>@ @g' | \
        awk '{print $1, $2}' | \
        sort | \
        awk '{print $2}'

Q5

Question

各行の数字を大きい順にソートしてください。

ueda@remote:~/tmp$ cat input 
A 31 1234 -42 4
B 10 31.1 -34 94

Answer

一番左の A と B がソートしないように大きな値にしておいて各列を行にして sort してみた。

$ cat input | while read f; do echo $f | awk '$1="99999999" $1{print}' | sed 's/ /\n/g' | sort -nr | tr '\n' ' ' | sed 's/99999999//'; echo ''; done
A 1234 31 4 -42
B 94 31.1 10 -34

Q6

Question

次のファイルについてグラフを作ってください。

ueda@remote:~/tmp$ cat num 
5
3
4
10
2

このような出力を作ります。

 5 *****
 3 ***
 4 ****
10 **********
 2 **

Answer

awk でベタにやってみた。

$ cat num | awk '{printf("%2d ", $1)}{for(i=0;i<$1;i++){printf("*")}print ""}'

Q7

Question

Q6のグラフを次のように縦にしてください。 (多少ズレてもよしとします。)

 * 
 * 
 * 
 * 
 * 
* * 
* * * 
* * * * 
* * * * *
* * * * *
5 3 4 10 2

Answer

なぜか解く気力がわかなかったので解答例を記載しておく。

ueda@remote:~/tmp$ cat num | 
awk '{printf $1" ";for(i=0;i<$1;i++){printf "* "}
for(i=$1;i<=15;i++){printf "_ "};print ""}' |
 awk '{for(i=1;i<=NF;i++){a[NR,i]=$i}}
END{for(i=1;i<=15;i++)
{for(j=1;j<=NR;j++){printf a[j,i]" "}print ""}}' | 
tac | sed -n '/\\*/,$p' | tr _ ' '

Q8

次のデータは、何かの試合の結果ですが、各チームが何勝何敗だったかを集計してください。引き分けは無いと仮定して構いません。

ueda@remote:~/tmp$ cat result 
A-B 1-2
B-A 3-1
C-A 1-0
B-C 5-4
C-B 2-1

Question

Answer

awk でベタベタにやってみた。

$ cat result | sed 's/-/ /g' | awk '{if($3>$4){w[$1]++; l[$2]++}else{w[$2]++; l[$1]++}}END{for(k in w){t[k]=k}; for(k in l){t[k]=k}; for(k in t){printf("%s %d win, %d lose \n", k, w[k], l[k])}}'
A 0 win, 3 lose
B 3 win, 1 lose
C 2 win, 1 lose

参考サイト