【問題と解答】第18回ニンニク入れますかシェル芸勉強会
Sat Aug 29 16:51:16 JST 2015 (modified: Sat Dec 14 18:35:47 JST 2019)
views: 3778, keywords:CLI,UNIX/Linuxサーバ,勉強会,シェル芸,シェル芸勉強会 この記事は最終更新日が6年以上前のものです。
問題だけのページはこちら: /?p=6877 過去問はこちら: /?page_id=684
オープニングスライド(悪い冗談)
問題で使うファイル等
今回からGitHubに置くようにしました。ファイルは
https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.18
にあります。
クローンは以下のようにお願いします。
$ git clone https://github.com/ryuichiueda/ShellGeiData.git環境
今回はLinuxで解答例を作りましたので、BSD系、Macな方は以下の表をご参考に・・・。
| Mac,BSD系 | Linux |
|---|---|
| gdate | date |
| gsed | sed |
| tail -r | tac |
| gtr | tr |
| gfold | fold |
Q1
次のファイルは1列目がキー、2列目が値ですが、「オトン」と「オカン」の両方の値があるキーを探してください。
$ cat text
001 オトン
001 オトン
001 アカン
002 オカン
003 オトン
003 ヤカン
003 オカン
004 オカン
005 オトン
005 ミカン
005 アカン解答
値がオトンとオカンのレコードを抽出してuniqで1列目が重複しているレコードを探します(解答例の出力の2列目は無視で)。
$ grep -e オトン -e オカン text | sort -u | uniq -w 3 -d
003 オカンQ2
次の2つのファイルについて、aだけにあるレコード、bだけにあるレコード、両方にあるレコードを分類して、
$ cat a
谷保
鹿島田
分倍河原
川崎
$ cat b
分倍河原
谷保
登戸
南多摩次のような出力を作ってください。
a 鹿島田
a 川崎
b 登戸
b 南多摩
c 谷保
c 分倍河原解答
commを使ってみたかっただけです。
$ comm <(sort a) <(sort b) | sed 's/^/\\t/' |
sed 's/\\t\\t\\t/c /' | sed 's/\\t\\t/b /' | sed 's/\\t/a /' | sort
a 鹿島田
a 川崎
b 登戸
b 南多摩
c 谷保
c 分倍河原
###別解###
$ grep '' a b | awk -F: '{print $2,$1}' |
awk '{a[$1]=a[$1]$2}END{for(k in a){print a[k],k}}' |
sed 's/ab/c/' | sort
a 鹿島田
a 川崎
b 登戸
b 南多摩
c 谷保
c 分倍河原Q3
次の3つのファイルについて、それぞれ書いてある数字の合計値を求めましょう。
$ cat a
1 2
3 4 5
$ cat b
1 2 3
$ cat c
7
8
9解答
どうやってファイル名と値の2列のデータにするかが鍵。
$ grep -o "[0-9]*" * |
awk -F: '{x[$1]+=$2}END{for(k in x){print k,x[k]}}'
a 15
b 6
c 24
###Tukubaiを使うと楽。###
$ grep -o "[0-9]*" * | tr : ' ' | sm2 1 1 2 2
a 15
b 6
c 24Q4
次のデータについて、
$ cat cross
_abcdef
a_x____
b______
c______
d______
e______
f___x__次のような出力を作ってください。
a-b
f-dつまり、xのついている場所の縦軸と横軸の記号を出力するワンライナーを考えてください。
解答
ベタにAWKを使うか、Tukubaiを使うか。
$ sed 's/./& /g' cross |
awk 'NR==1{split($0,a," ")}
/x/{for(i=1;i<=7;i++){if($i=="x"){print $1 "-" a[i]}}}'
###Tukubai使用###
$ sed 's/./& /g' cross | unmap num=1 |
awk '/x/{print $1 "-" $2}'Q5
次のテキストから空白行の重複だけ除去してください。つまり、2行以上の空白行を1行にまとめてください。
あ
あ
い
い
う
え
お お
お
お解答
文字のある行にだけ番号をつけてuniqすればよいですね。
$ grep -n '' text | sed 's/.*:$//' | uniq | sed 's/.*://'
あ
あ
い
い
う
え
お お
お
お
###別解###
$ awk '$1{print NR,$0}!$1' text | uniq | sed 's/^[0-9]* //'
###ebanさんを始めオプションを知っている人の答え(恐れ入りました)###
$ cat -s textQ6
チェスボードの画像ファイルを作ってください。ウェブサイトから画像をパクるのは最近いろいろ問題となっているのでやめましょう。以下は例です。解像度は任意で構いません。
解答
PGM形式で画像を作るのが一番簡単です。
$ yes '0 1 0 1 0 1 0 1' |
head -n 8 | sed '1~2s/0 1/1 0/g' | cat <(echo "P2 8 8 1") - > a.pgm
###AWKを使う場合###
$ seq 1 64 | awk '{print ($1 + int((NR-1)/8))%2}' |
xargs -n 8 | awk 'BEGIN{print "P2",8,8,1}{print}' > a.pgmpgmが見れない。あるいは8x8ピクセルだとヤダという場合はImageMagickで変換を。
$ convert -scale 400 a.pgm a.pngQ7
次のファイルには1組だけ同じ文字が含まれていますが、何行目と何行目にあるでしょうか?
$ cat chinese_characters
㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏
㔐㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜㔝㔞㔟
㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯
㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿
㕀㕁㕂㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌㕍㕎㕏
㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟
㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯
㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿
㖀㖁㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌㖍㖎㖏
㖐㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜㖝㖞㖟
㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯
㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿
㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㕐㗊㗋㗌㗍㗎
㗐㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜㗝㗞㗟
㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯
㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿解答
同じファイルをワンライナーで二回読み込みます。
$ grep -o . chinese_characters | LANG=C sort |
LANG=C uniq -d | grep -f - -n chinese_characters
6:㕐㕑㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜㕝㕞㕟
13:㗀㗁㗂㗃㗄㗅㗆㗇㗈㗉㕐㗊㗋㗌㗍㗎LANG=Cをちゃんと付けないとダメなようです。
###間違い###
$ grep -o . chinese_characters | sort |
uniq -d | grep -f - -n chinese_characters
1:㔀㔁㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌㔍㔎㔏Q8
次のファイルの中に、複数回登場する数字の並びがいくつかありますが、その中で最長のものはどれでしょうか?例えば「23」という数字の並びは4つありますが、それより長い数字の列で、2回以上登場するものが存在します。
$ cat number
8264611130023148519839960536022802096895154738213681101003238003191122723922378922942503388843815799解答
どうやって数字の並びを全通り出力するかがミソです。以下の出力のように003と922が正解です。
$ cat number |
awk '{for(j=1;j<length($1);j++)for(i=1;i<=length($1)-j+1;i++){print substr($1,i,j)}}' |
sort | uniq -d | awk '{print length($1),$1}' | sort -k1,1n
...
2 99
3 003
3 922
ノート
Tweet