日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です。微力ながら共著させていただいた「シェル・ワンライナー160本ノック」をよろしくお願い申し上げます。

第20回シェル芸勉強会へ遠隔参加

第20回シェル芸勉強会の福岡サテライト会場を開設させていただきました。寒いです!おまけに年の瀬であるにも関わらず、ご参加いただきありがとございました。素晴らしい会場をご提供いただきありがとうございます。

問題作成と解説の上田さん、会場管理者さん、ありがとうございます。参加者の皆さまお疲れ様でした。そしてまた写真撮るの忘れました・・・

勉強会の情報

問題と解答

勉強会主催の上田さんが公開されているページをご覧ください。 b.ueda.tech

会場情報

東京の本家勉強会案内はこちら。 usptomo.doorkeeper.jp

福岡サテライトの案内はこちら。 https://atnd.org/events/72720atnd.org

午前中の部

今回は午前中が斎藤さんによる初心者向けの内容でした。 午前中からUstreamによる参加で予定していましたが、最初の流れに乗りそこなっちゃいました。 そこで、斎藤さんが事前に配布されていた資料のPDFを使わせていただき、awkの解説を話しました。

,で範囲指定とか、後半は実は知らなかったことが結構あって、勉強になりました。 アクションを使わずにパターンだけで処理するのが新鮮でした。資料とサンプルデータはこちらです。

awk勉強会で時間的にも手一杯、後半のシェル変数展開に関する話題は出来ませんでした。

昼食は近くの餃子王将に皆さんでお出かけしました。お仕事どんなことしてるのかとか、最近のsamba事情!?とかの話題があがりました。 samba・・・そう言えば最近最新の状況とか追いかけてませんでした。

会場に帰ってからは、皆さんの環境作成とかをしたりしました。今回はmacOS、Debian、FreeBSDなど環境が色々でした。 X Window System無しのFreeBSDで、コンソールに直接ログインされていた方もいらっしゃいましたが、日本語の扱いに問題ありでした。 TeraTermなど日本語入出力が可能な端末エミュレータが必要など、事前のアナウンスが必要かもしれないと思いました。

午後の部

今回の問題もなかなか手強いと思いました。 ギブアップな問題があったり、そもそも問題の意味を取り違えたりしていたのもありました。 問題を解くというよりは、参加者の方の理解をサポートすることを重視しました。 自分なりに頑張ってみたのですが、どうだったでしょうか?

以下、各問題について私なりの解答と、参加者の方への説明を記載します。

Q1

まずはウォーミングアップ的な問題。

先に私が解いた後、参加者の方に解き方と考え方の説明を行った。私が考えた解答例はこちらです。

$ grep '' * | tr ':' ' ' | self 1.1.6 2 | sort -k1,1 -k2,2n |
 getlast 1 1
$ grep '' * | tr ':' ' ' |
 awk '{if(a[substr($1,1,6)]<$2){a[substr($1,1,6)]=$2}}END{for(v in a){print v,a[v]}}'

まずgrep '' *で、ファイル名とファイルの内容を表示するというところを説明しました。

$ grep '' *
file_A-1:1
file_A-1:31351
....
file_B-2:9912
file_B-2:4488

次にファイル名をfile_Aとfile_Bの部分を切り出します。

$ grep '' * | tr ':' ' ' | self 1.1.6 2
file_A 1
file_A 31351
....
file_B 9912
file_B 4488

次にファイル名で並べ替え、Tukubaiのgetlastで最後の列を表示して完成です。

$ grep '' * | tr ':' ' ' | self 1.1.6 2 | sort -k1,1 -k2,2n | getlast 1 1
file_A 233333
file_B 9912

もう一つの解答はawk芸です。連想配列を使ってより最大値を探す説明をしました。

Q2

スクレイピングの問題。

これも先に私が解いてから説明を行ないました。

$ curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | sed -n '/<pre>/,/<\/pre>/p' | sed -n '9p' | sed 's/^.*$ //' | sh

sedの説明にちょうど良い問題となった。sedで必要な部分を切り出していけば良い。UNIXではシェルもコマンドの一つに過ぎないので、コマンド文字列をパイプで流し込むことで実行出来ることを補足した。

Q3

これは完全に問題の意図を読み間違えており、奇数行と偶数行を分割すると思い込んでいました。 数値自体が奇数か偶数か?で分割する問題でした。

問題の意味を取り違えたまま、奇数行を1列目、偶数行を2列目に分ける方法を下記のように解説してしまいました。 参加者の皆様申し訳ありませんでした。xargsについては、のちに本来の使い方を説明しました。

$ seq 1 4 | awk 'NR%2==0{print}NR%2{printf $0" "}'
1 2
3 4

$ seq 1 4 | xargs -n2
1 2
3 4

$ cat Q3 | yarr -2
1 2
3 4

Q4

こ、これわ・・・とりあえず下記のような解答をしました。(一応動いた)

$ ps x | grep grep | self 2 | ggrep -vf - <(ps x | grep bash) | self 1 | xargs kill

これについては、前半でkillするプロセスIDのリストを作ってxargs killに渡すという流れを説明しました。 あまり時間が取れなかったので、考え方を聞いてもらって詳しいことは割愛しました。 xargsについては使い方の補足を話しました。

追記

本家解答例がLinux版なので、macOS用も作りました。

$ a=$(tty | sed 's;/dev/tty;;') ; ps aux | awk '$7~/s[0-9]*/' | awk -v "t=$a" '$7!=t' | awk '{print $2}' | xargs kill

Q5

ギ、ギブアップです・・・

ということで、素因数分解が出来るfactorコマンドの紹介と説明、素数列挙方法の説明をしました。

$ seq 10 | gfactor
1:
2: 2
3: 3
....
8: 2 2 2
9: 3 3
10: 2 5

素数の場合は列数が2になります。awkで2列の場合のみ表示して完成です。

$ seq 10 | gfactor | awk 'NF==2{print $2}'
2
3
5
7

Q6

Tukubai便利なので・・・Tukubai芸で解いちゃいました。

$ cat Q6 | tr ' ' ' ' | juni | tarr num=1 | juni 1 1 | self 3 1 | sort -k1,1 | yarr num=1

まずは行番号をつけてデータを縦に並べます。まずはこの発想が重要かもしれません。

$ cat Q6 | tr ' ' ' ' | juni | tarr num=1
1 山田
1 上田
1 吉田
1 武田
2 吉田
2 武田
2 上田
2 山田

次にTukubaiのjuniコマンド本来の使い方で、キーが同じ範囲でカウントアップします。 これで、列番号、行番号、データの順番で表示出来ます。

$ cat Q6 | tr ' ' ' ' | juni | tarr num=1 | juni 1 1
1 1 山田
2 1 上田
3 1 吉田
4 1 武田
1 2 吉田
2 2 武田
3 2 上田
4 2 山田

次に列番号とデータだけを抜き出し、適宜並べ替え処理します。yarrで列番号を横に並べて完成です。

$ cat Q6 | tr ' ' ' ' | juni | tarr num=1 | juni 1 1 | self 3 1 |
 sort -k1,1 | yarr num=1
上田 2 3
吉田 1 3
山田 1 4
武田 2 4

Q7

ギ、ギブアップです・・・・

出題者上田さんの解答例を理解した後、会場の方に説明をしました。

それから余談で、bcコマンドの使い方について説明をしました。例えば16進数で出力するやり方はこんな感じです。

$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
obase=16 <=入力
10
A <= 入力
100
64 <= 入力
quit

10進数で1から100までを16進数で表示する場合の説明をしました。

$ seq 16 | ( echo obase=16; cat ) | bc
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
10

Q8

これもギブアップです・・・

ということで、とりあえず下記のようにtrコマンドとsedコマンドの同様な使い方について説明しました。

$ cat Q8 | tr '一二三四五六七八九' '123456789'
5千7百3十5
4千3
4十5
9万6千2百3十3
十1
百十2

$ cat Q8 | sed 'y/一二三四五六七八九/123456789/'
5千7百3十5
4千3
4十5
9万6千2百3十3
十1
百十2

最後にxargsの使い方など補足の説明を行って終了しました。 やはり内容の多さに対して時間が短い・・・というのが悩みです。

こういうUNIXのコマンドやシェルを使った操作などはどうやって勉強したりすれば良いのか?という質問がありました。 実践的に手を動かすための機会や題材が無い、という印象でした。 今回は勉強会主催者上田さん著書のシェル芸本2冊や、UECのWebサイトを紹介させていただきましたが、 やはり自分だけでやるには余程モチベーションが無いと難しいのかもしれないと思いました。 初心者向けシェル芸勉強会をどう展開していくか?を考えることにもつながりそうです。