シェル芸スパルタン演習(第20回シェル芸勉強会編)
ここ最近、Unixシェルに触る機会が減っており、CLIを使う能力の低下を感じていた。
また、近日中に、第25回シェル芸勉強会の開催が予定されており、参加するにあたり予習をしたいとも考えていた。
そこで、過去に開催されたシェル芸勉強会の問題を活用し、シェル芸力をつける演習をおこなうことにした。
今回は、問題として、第20回シェル芸勉強会の設問を用いた。
実行環境
Arch Linux 4.8.4-1-ARCH
GNU bash 4.3.46
GNU coreutils 8.25-2
GNU diffutils 3.5-1
GNU findutils 4.6.0-2
util-linux 2.28.2-1
grep (GNU grep) 2.26
GNU bc 1.06.95
sed (GNU sed) 4.2.2
gawk 4.1.4
curl 7.50.3
usp Personal Tukubai 20160402 ( Open usp Tukubaiで代用可能)
シェル芸演習
問題文は、以下のURLから。
https://blog.ueda.asia/?p=7332
模範解答は、こちらから。
https://blog.ueda.asia/?p=7196
問1
グルーピングされたファイルから、グループ毎に最大の数値を求める問題。
awkの特殊変数FILENAMEを利用し、正規表現でグルーピング部分を切り出して利用する。
後は、グループ毎に最大値を求めるだけ。
01 #!/bin/sh
02
03 gawk '{print gensub(/-.*$/, "", "g", FILENAME), $0}' ./* |
04 sort -k 1,1 -k 2,2nr |
05 awk '$1 != group{print; group=$1}'
以下、コピペ実行用のワンライナーコード。
gawk '{print gensub(/-.*$/, "", "g", FILENAME), $0}' ./* | sort -k 1,1 -k 2,2nr | awk '$1 != group{print; group=$1}'
問2
アンサイクロペディアの記事から、特定のシェル芸を抽出して実行する問題。
HTMLソースから該当する部分を削り出していき、最後にshに入力するだけ。
01 #!/bin/sh
02
03 curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 |
04 grep -A 4 'カースト最上位者が日常的に書く、素数を出力するワンライナー' |
05 sed -n '4{s/^[$] //; p}' |
06 sh
以下、コピペ実行用のワンライナーコード。
curl -s http://ja.uncyclopedia.info/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8 | grep -A 4 'カースト最上位者が日常的に書く、素数を出力するワンライナー' | sed -n '4{s/^[$] //; p}' | sh
問3
奇数、偶数毎に、異なった方法でソートする問題。
奇数、偶数が混じった状態でソートするのではなく、それぞれ個別にソートした後、結合するのがポイント。
01 #!/bin/bash
02
03 paste <(cat Q3 |awk '$0%2==1' |sort -n) <(cat Q3 |awk '$0%2==0' |sort -nr) |
04 awk '$1=$1'
以下、コピペ実行用のワンライナーコード。
paste <(cat Q3 | awk '$0%2==1' | sort -n) <(cat Q3 | awk '$0%2==0' | sort -nr) | awk '$1=$1'
問4
自分の端末以外をkillする問題。
環境的に怖くて試せなかったので、本当にこれで正解なのかは分からない…
01 #!/bin/sh
02
03 (tty; ps aux |awk '$7 ~ /pts\/[0-9]*/') |
04 awk 'NR==1{sub(/\/dev\//, "", $0); tty=$0} NR!=1 && $7 !~ tty{print $2}' #| xargs sudo kill
以下、コピペ実行用のワンライナーコード。
(tty; ps aux |awk '$7 ~ /pts\/[0-9]*/') | awk 'NR==1{sub(/\/dev\//, "", $0); tty=$0} NR!=1 && $7 !~ tty{print $2}' #| xargs sudo kill
問5
任意の自然数2つについて、最大公約数を求める問題。
手前味噌だけれど、Project Eulerの この問題[http://qiita.com/gin_135/items/f633fa0e0897878fcd10] を参考にして、最大公約数を求めれば良い。
01 #!/bin/sh
02
03 echo $((RANDOM % 100)) $((RANDOM % 100)) |
04 tr ' ' '\n' |
05 sort -nr |
06 xargs |
07 awk 'func gcd(m,n){if(n==0){print m; exit} gcd(n,m%n)} {print $1,$2; gcd($1,$2)}'
以下、コピペ実行用のワンライナーコード。
echo $((RANDOM % 100)) $((RANDOM % 100)) | tr ' ' '\n' | sort -nr | xargs | awk 'func gcd(m,n){if(n==0){print m; exit} gcd(n,m%n)} {print $1,$2; gcd($1,$2)}'
問6
ファイルに記載されている人名について、それぞれ行列番号を求める問題。
awkの連想配列を活用して、ざっくりと。
01 #!/bin/sh
02
03 cat Q6 |
04 nl |
05 tr ' ' ' ' |
06 awk '{for(i=2;i<=NF;i++){print $i,$1,i-1}}' |
07 sort -k 1,1 -k 2,2n |
08 awk '{mem[$1]=mem[$1]" "$2" "$3} END{for(n in mem){print n,mem[n]}}' |
09 awk '{print $1,$3,$5}'
Tukubai版。大まかな方針は、上記の方法と同じ。
01 #!/bin/sh
02
03 cat Q6 |
04 nl |
05 tr ' ' ' ' |
06 awk '{for(i=2;i<=NF;i++){print $i,$1,i-1}}' |
07 sort -k 1,1 -k 2,2n |
08 yarr num=1 |
09 awk '{print $1,$3,$5}'
以下、コピペ実行用のワンライナーコード。
cat Q6 | nl | tr ' ' ' ' | awk '{for(i=2;i<=NF;i++){print $i,$1,i-1}}' | sort -k 1,1 -k 2,2n | awk '{mem[$1]=mem[$1]" "$2" "$3} END{for(n in mem){print n,mem[n]}}' | awk '{print $1,$3,$5}'
cat Q6 | nl | tr ' ' ' ' | awk '{for(i=2;i<=NF;i++){print $i,$1,i-1}}' | sort -k 1,1 -k 2,2n | yarr num=1 | awk '{print $1,$3,$5}'
問7
「魚」の部分を持つ漢字を列挙する問題。
網羅しているとは言えないけれど… 沢山列挙されているWebサイトから取得する。
01 #!/bin/sh
02
03 curl -s http://rtk.art.coocan.jp/cjk/rads/195.html |
04 grep -o 'TITLE="[^ "]* ' |
05 sed 's/.*【\(.\)】/\1/'
以下、コピペ実行用のワンライナーコード。
curl -s http://rtk.art.coocan.jp/cjk/rads/195.html | grep -o 'TITLE="[^ "]* ' | sed 's/.*【\(.\)】/\1/'
問8
漢数字をアラビア数字に変換する問題。
単純そうに見えて、実はかなり厄介な問題。
漢数字とアラビア数字では、位取り記法が異なるので、それを変換しつつ、漢字を数字に変換する。
01 #!/bin/sh
02
03 cat Q8 |
04 sed 'y/一二三四五六七八九/123456789/' |
05 sed 's/.$/@&/' |
06 tr -d '\n' |
07 grep -o . |
08 sed '/@/{N; s/\n//}' |
09 sed 's/十/1*10/; s/百/1*100/; s/千/1*1000/; s/万/1*10000/' |
10 xargs |
11 sed 's/@. /&\n/g' |
12 sed 's/\(.\) \(1\*\)/\1*\2/g' |
13 tr ' ' '+' |
14 sed 's/@\(.\)+*$/\1/g' |
15 bc
以下、コピペ実行用のワンライナーコード。
cat Q8 | sed 'y/一二三四五六七八九/123456789/' | sed 's/.$/@&/' | tr -d '\n' | grep -o . | sed '/@/{N; s/\n//}' | sed 's/十/1*10/; s/百/1*100/; s/千/1*1000/; s/万/1*10000/' | xargs | sed 's/@. /&\n/g' | sed 's/\(.\) \(1\*\)/\1*\2/g' | tr ' ' '+' | sed 's/@\(.\)+*$/\1/g' | bc
雑記
わん!
ゲンキの視線が斜め上に向いている時の、ちょっととぼけたような、あどけないような表情が、すごく好きです。何だか元気が出てきます。 2016.07.13(水) #東山動物園 #シンリンオオカミ ゲンキ pic.twitter.com/xQnNdtkdj2
— ginjiro (@gin_135) 2016年8月16日