「第20回記念、年末年始の浮ついた気分大粉砕シェル芸勉強会」を簡単に復習
はじめに
今回のシェル芸勉強会は、Ustream経由にて遠隔参加しました。
なお、年末進行により記事を書く時間の確保が難しかったため、説明は最小限になりますことをあらかじめご了承のほどお願いします。
勉強会の詳細および問題・模範解答などは次の通りです:
- jus共催、第2回今度は絶対初心者向け午前のシェル勉強会/第20回記念、年末年始の浮ついた気分大粉砕シェル芸勉強会/第37回ふわふわUSP友の会定例会 - USP友の会
- 【問題と解答】第20回記念、年末年始の浮ついた気分大粉砕シェル芸勉強会 - 上田ブログ
- jus共催、第2回今度は絶対初心者向け午前のシェル勉強会/第20回記念、年末年始の浮ついた気分大粉砕シェル芸勉強会/第37回ふわふわUSP友の会定例会 - Togetterまとめ
A1(グループ内の最大数を探す):
グループが「A〜Z」まで存在すると仮定して、グループごとにまとめてcatした後にsort -nします。
$ for N in {A..Z} ;do ls file_${N}* 2>/dev/null; cat file_${N}* 2>/dev/null | sort -n | tail -n1; done
file_A-1 file_A-2
233333
file_B-1 file_B-2
9912
エラーは/dev/nullに捨てておきます。
A2(Webページからコードを取得して実行):
取り込んだWebページに行番号を付け、必要な行のみ取り出してsedで行頭の不要な部分を取り除きます。
$ w3m -dump http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | cat -n | awk 'NR==77' | sed 's/^.*$ //' | bash
2
3
5
(...中略...)
983
991
997
grepで必要な行を抽出した別解です。
$ w3m -dump http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep -F '$ eval eval ' | sed 's/^$ //' | bash
2
3
5
(...中略...)
983
991
997
この別解のほうが正攻法だと思います。
A3(奇数列を昇順、偶数列を降順にソート):
与えられた条件でsortした各列をpasteで結合します。
$ paste -d ' ' <(awk '$1%2' Q3 | sort -n) <(awk '!($1%2)' Q3 | sort -nr)
1 8
5 4
9 2
A4(自分以外が使っている端末をkill):
この問題については、全く時間が足りませんでした。
問題で想定されている環境がないため、これが正解かどうか分かりませんが恐らくこんな感じになると思います。
$ t=$(tty); ps -e | awk '$2~/^pts\/[0-9]+$/{print "/dev/"$2,$1}' | grep -v "^$t " | awk '{print $2}' | sudo xargs kill
途中のgrepで検索パターンとしてttyの結果を使いますが、あらかじめttyの結果をシェル変数に代入してから使わなければならないことに注意が必要です。
A5(最大公約数を求める):
Q5と次のQ6を解いているあいだ、TweetDeckがらみでWebブラウザ(Iceweasel)のクラッシュが頻発したため解答をツイートできなかったのが悔やまれます……。
シンプルにPerlで解いてみました。
$ echo 111 185 | perl -ae 'sub gcd{$_[1]?gcd($_[1],$_[0]%$_[1]):$_[0]};print gcd(@F),"\n"' -
37
A6(誰が1列目と2列目の何番めに記述されているかを求める):
名前に行と列の番号を付けてから名前でsortし、重複している名前を取り除きます。
$ cat Q6 | awk -F ' ' '{for(i=1;i<=NF;i++){print $i" "NR" "i}}' | sort -k1,1 | awk '{printf($1!=p?$1" "$3:" "$3"\n");p=$1}'
吉田 3 1
山田 1 4
上田 2 3
武田 4 2
A7(部首が「魚」の漢字を列挙):
「【みんなの知識 ちょっと便利帳】ユニコード・CJK統合漢字「魚部」の漢字 - 部首による漢字の読み方 - 魚部「魚/うお,さかな・魚偏/うおへん,さかなへん」の漢字」のデータを参考にしました。
$ for n in $(seq 19506 19620;seq 39770 40164); do echo "&#"${n}";" | nkf --numchar-input; done
䰲
䰳
䰴
(...中略...)
鳢
鳣
鳤
Perlによる別解です。
$ perl -E 'binmode(STDOUT,":utf8");for(0x4C32..0x4CA4,0x9B5A..0x9CE4){$_=sprintf "%X",$_;s/([\dA-F]{4})/chr hex $1/eg;say}'
䰲
䰳
䰴
(...中略...)
鳢
鳣
鳤
A8(漢数字をアラビア数字に変換):
Q2の応用ということで、「漢数字を計算数字、英語に変換」を利用してみました。
$ cat Q8 | xargs -I@ bash -c "w3m -dump http://www.sljfaq.org/cgi/kanjinumbers_ja.cgi?kanjiin=@ | cat -n | awk 'NR==41'" | awk '{print $3}'
5,735
4,003
45
96,233
11
112
真面目にsedを使った別解です。
$ cat Q8 | sed -e 'y/一二三四五六七八九/123456789/;s/万/*10000+/;s/千/*1000+/;s/百/*100+/;s/十/*10+/;s/^\*//;s/+$//;s/+\*/+/' | bc
5735
4003
45
96233
11
112
おわりに
今回気づいたこと:
- サーバ関連の知識が全く足りていない
- Webスクレイピングとシェル芸は相性が良い
- シェル芸界隈における「初心者」の意味は一般のそれとは異なる
それでは皆さん、良い年末年始を。