シェル力が圧倒的に足りてないのでシェル力を養うために第12回シェル芸勉強会の問題に挑戦してみた。
シェル力が圧倒的に足りてないのでシェル力を養うために第12回シェル芸勉強会の問題に挑戦してみた。
問題はすごく工夫してあってパズル感覚で解けて楽しいしシェル力を養うのにも役立ちそう。
自分が使ってる zsh のバージョン。
$ zsh --version zsh 5.8 (x86_64-apple-darwin19.6.0)
はじめに
自分はシェル力が圧倒的に足りてないので勉強のためにシェル芸勉強会の問題に挑戦してみた。
一応自分がシェルを使う用途を書いておくと普段の仕事は Mac を使ってやっててちょっとしたことをやるのにちょろっとシェルを使う程度。
ちなみにシェル芸ってなに? ってところは Wikipedia の USP 友の会 から引用しておく。
シェル芸とは、主に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 せめて XML か CSV で公開してほしい。
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 なのが惜しいけど nkf で UTF-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