シェル芸初心者向け勉強会に後日自宅にてサテライト参加(参加とは言わない)【後半】

さて、ここからシェル芸勉強会の過去問です。シェル芸勉強会の方は"「コワイ」のイメージが先行して敷居が高い"のでawk縛りとかawk使わない縛りとかいうことは言わずに解きます。

シェル芸勉強会過去問第2回 問題1: 文字化けしたファイルの削除

問題

次のように、空ファイル abc, DEFG と、文字化けした空ファイルを作ってください。【今回は問題データのQ1ディレクトリ以下に作成済み】

$ touch abc
$ touch DEFG
$ echo ほげ | nkf -s | xargs touch
$ ls

%82ق%B0        DEFG        abc

解法

rm $(ls | grep -a -v [A-z])

解説

今回は文字化けどころではなく[A-z]を含まないファイルを全部消しました。

シェル芸勉強会過去問第2回 問題2: 計算

問題

以下のファイル中の数字を全部足し算してください。

$ cat Q2/num

1
2 3 4
5 6
7 8 9 10

解法

==

cat /tmp/num | tr "\n " + | sed 's/+$/\n/' | bc

解説

前述の通りこういう問題は式をいじって最後に評価するタイプの解法が好きなのでこう解きました。

シェル芸勉強会過去問第2回 問題3: 条件でデータを取り出し

問題

下のhogeファイルから、aとbについてそれぞれ一番大きな数を求めましょう。

$ cat Q3/hoge

a 12
a 13
b 13
a 432
b 111
b 43

解法

==

awk '{if(s[$1] < $2){s[$1]=$2}}END{for(i in s){print i,s[i]}}'

解説

なんかここまで普通に書くと負けた気がするので怪しい解ですが ==

cat /tmp/hoge | sed 's/a/000/;s/b/999/' | tr -d " " | sort -rn | sed 's/000/a /;s/999/b /' | uniq -w 1

というものも作ってみました。

シェル芸勉強会過去問第2回 問題4: 計算

問題

以下のファイル中の数字を、キー(a,b)ごとに全部足し算してください。

$ cat Q4/num2

a 1
b 2 3 4
a 5 6
b 7 8 9 10

解法

cat /tmp/num2  | awk '{for(i=2;i<=NF;i++){s[$1]+=$i}}END{for (i in s){print i,s[i]}}'
cat /tmp/num2  | sort | sed 's/\([0-9]\) /\1+/g;s/ /+=/' | cat - <(echo a;echo b) | bc

解説

bcを使ったほうがたのしいよ!

シェル芸勉強会過去問第2回 問題5: 日付と曜日

問題

以下のようにファイルを作って、何曜日が何日あるか集計してください。【今回は問題データのQ5ディレクトリ以下に作成済み】

$ seq 1990 2012 | awk '{print $1 "0101"}' > osyoga2
$ head -n 5 osyoga2

19900101
19910101
19920101
19930101
19940101

解法

cat /tmp/osyoga2 | xargs -I{} date --date={} +%u | sort | uniq -c

解説

date使って曜日を計算させました。さっきから集計のときに=sort | uniq -c=ばっかり使ってますね。

シェル芸勉強会過去問第2回 問題6: ダミーデータの作成

問題

seq 1 100 の出力をランダムに並び替えてください。

解法

seq 1 100 | shuf

解説

shufという便利な(?)コマンドがcoreutilsにあります。awkで解くのは嫌です。

シェル芸勉強会過去問第2回 問題7: 検索

問題

大文字小文字を区別しない場合、以下の辞書ファイルから、重複する単語を検索してください。 asciiコード以外の字がありますが、 とりあえず気にしないでください。

$ head Q7/words

A
A's
AA's
AB's
ABM's
AC's
ACTH's
AI's
AIDS's
AM's

解法

cat words | tr '[:upper:]' '[:lower:]' | sort | uniq -d

解説

とりあえず全部小文字にして重複文字を出しましたがこれでいいんでしょうか?

シェル芸勉強会過去問第2回 問題8: ファイルの比較

問題

file2から、file1にない数字を抽出してください。

$ cat Q8/file1

1
3
4
6
9

$ cat Q8/file2

2
3
4
5
9

解法

grep -v -f file1 file2

解説

grepの逆マッチ、ファイル入力版です。

シェル芸勉強会過去問第2回 問題9: 形式変換

問題

gameから、resultように整形してください。

$ cat Q9/game

1 表 2
1 裏 2
2 表 0
2 裏 1
3 表 3
3 裏 0
4 表 3
4 裏 0
5 表 0
5 裏 0

$ cat Q9/results

   1 2 3 4 5
表 2 0 3 3 0
裏 2 1 0 0 0

解法

cat game | awk '$2=="表"{omote[$1]=$3}$2=="裏"{ura[$1]=$3}END{printf "  ";for (i=1;i<=NR/2;i++){printf " %d",i} printf "\n表";for (i=1;i<=NR/2;i++){printf " %d",omote[i]} printf "\n裏";for (i=1;i<=NR/2;i++){printf " %d",ura[i]} printf "\n"}'
cat game | awk '{score[$2=="裏"][$1]=$3}END{printf "  ";for (i=1;i<=NR/2;i++){printf " %d",i} for(j=0;j<2;j++){printf "\n%s",j?"裏":"表";for (i=1;i<=NR/2;i++){printf " %d",score[j][i]}} printf "\n"}'

解説

awkの配列に入れて最後にforで取り出しました。あまりの泥臭さに少しなんとかしましたがもっと良い解法があるはず。

シェル芸勉強会過去問第2回 問題10: ファイルの結合

問題

file1、file2 から、下の出力を得てください。

$ cat Q10/file1

001 うそ
002 笑止
003 矢追純

$ cat Q10/file2

001 800
002 10000000
003 1

欲しい出力

001 うそ 800
002 笑止 10000000
003 矢追純 1

解法

cut -d ' ' -f 2 file2 | paste -d ' ' file1 -

解説

横結合はpasteでできますが、流石に題意を取り違えているような気がする。