【問題と解答】jus共催 第30回危念シェル芸勉強会
Sat Aug 26 15:52:53 JST 2017 (modified: Sun Oct 1 10:50:27 JST 2017)
views: 3574, keywords:コマンド,CLI,Linux,シェル芸,シェル芸勉強会 この記事は最終更新日が7年以上前のものです。
問題で使うファイル等
GitHubにあります。ファイルは
https://github.com/ryuichiueda/ShellGeiData/tree/master/vol.30
にあります。
クローンは以下のようにお願いします。
git clone https://github.com/ryuichiueda/ShellGeiData.git $
環境
解答例はUbuntu Linux 16.04 で作成。Macの場合はcoreutilsをインストールすると、GNUのコマンドが使えます。BSD系の人は玄人なので各自対応のこと。
イントロ
Q1
リポジトリの中に、次のようなディレクトリがあります。
tree posts
$ posts
20170806_check_of_webhook
├── main.md
│ └── 20170810_negi
├── green_negi.jpg
│ ├── main.md
│ ├── white_negi.jpg
│ ├── .pdf
│ └── ねぎ20170810_negistagram
├── main.md
│ └── 20170812_work
├── 20170812_working
├── main.md
│ └── 20170814_layout
├── main.md
│ └── 20170818_bash
├── main.md
│ └── 20170820_bootstrap
├── main.md
│ └── 20170820_injection
├── main.md
│ └── template
└── main.md └──
この中の、各main.mdは次のようなヘッダ付きのマークダウンです。
cat posts/20170818_bash/main.md
$ ---
Keywords: 嫌がらせ
Copyright: (C) 2017 Ryuichi Ueda
---
# 検索機能への嫌がらせ
Keywords: ワッショイ
Keywords: ワッショイ
Keywords: ワッショイ
これらのファイルから、次のような出力を作ってください。なお、Keywordsの行は各ファイルで最初にある行しか抽出しないこととします。
20170806_check_of_webhook Keywords: Webhook
20170810_negi Keywords: ネギ
20170810_negistagram Keywords: Twitter, Instagram, ネギ
20170812_working Keywords: 働けども働けども, bashcms2
20170814_layout Keywords: table, 雑
20170818_bash Keywords: 嫌がらせ
20170820_bootstrap Keywords: Bootstrap
20170820_injection Keywords: injection
template Keywords:
解答
grepの-mオプションを使うと一番最初にマッチした行を取り出せます。
grep -m 1 '^Keywords:' posts/*/main.md |
$ sed 's;posts/;;' | sed 's;/main.md:; ;'
Q2
次のHTMLファイルurl.htmlについて、リンクが相対パスになっているものについては頭に/files/をつけて、/から始まっているものとhttpやhttpsから始まっているものはそのままにしてください。できる人は変なところに改行があるものなどに対応できるように、なるべく一般解に近づけましょう。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<ul>
<li><a href="./hoge.html">ほげ</a></li>
<li><img src="ayasii.jpg" alt="怪しい" /></li>
<li><a href="https://blog.ueda.tech/">クソブログ</a><a href="huge.html">ふげ</a></li>
<li><a href="/root.jpg"></a>これはそのまま</li>
<li><a href="http://www.usptomo.com/">更新してない</a></li>
</ul>
</body>
</html>
次が出力例です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<ul>
<li><a href="/files/hoge.html">ほげ</a></li>
<li><img src="/files/ayasii.jpg" alt="怪しい" /></li>
<li><a href="https://blog.ueda.tech/">クソブログ</a><a href="/files/huge.html">ふげ</a></li>
<li><a href="/root.jpg"></a>これはそのまま</li>
<li><a href="http://www.usptomo.com/">更新してない</a></li>
</ul>
</body>
</html>
解答
いちおうこれで大丈夫だとは思うのですが、自分でもなんだかよくわかりません・・・。
cat url.html | sed -r 's;(img src="|a href=");&/files/;g' |
$ sed -r 's;(href="|src=")/files//;\\1/;' |
sed -r 's;(href="|src=")/files/(https://|http://);\\1\\2;g' |
sed 's;/./;/;g'
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<ul>
<li><a href="/files/hoge.html">ほげ</a></li>
<li><img src="/files/ayasii.jpg" alt="怪しい" /></li>
<li><a href="https://blog.ueda.tech/">クソブログ</a><a href="/files/huge.html">ふげ</a></li>
<li><a href="/root.jpg"></a>これはそのまま</li>
<li><a href="http://www.usptomo.com/">更新してない</a></li>
</ul>
</body>
</html>
Q3
次のファイルについて、
cat list
$ * 妬み
* 嫉み
* 僻み
次のようにHTMLにして、頭にHTTPヘッダをつけてください。インデントは不要ですがタグは1行1個でお願いします。
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<ul>
<li>妬み</li>
<li>嫉み</li>
<li>僻み</li>
</ul>
</body>
</html>
すぐできて退屈な人は、インターネット上のサーバでこのHTMLファイルを送信するサーバをワンライナーで立ててください。
解答
ゴリゴリやってもあまり苦労はしないと思いますが、Pandocの紹介がてら問題を出しました。cat list | sed 's/\\* /<li>/' | sed 's;$;</li>;' |
$ sed '1iContent-Type: text/html\\n\\n<!DOCTYPE html><html><head><meta charset="utf-8"></head><body><ul>' |
sed '$a</ul></body></html>' | sed 's/></>\\n</g'
### Pandocを使う方法 ###
pandoc list -t html5 -s | sed '5,12d' | sed '1iContent-Type: text/html\\n' $
ブラウザからの応答に反応するには、レスポンス行も追加します。(改行は\r\nの方がいいかもしれません。)
pandoc list -t html5 -s | sed '5,12d' |
$ sed '1iHTTP/1.1 200 OK\\nContent-Type: text/html\\n' | nc -l 8080
### 連続応答 ###
while : ; do pandoc list -t html5 -s | sed '5,12d' |
$ sed '1iHTTP/1.1 200 OK\\nContent-Type: text/html\\n' | nc -l 8080 ; done
Q4
&&や;でコマンドを繋いだワンライナーで、GitHubにリポジトリを作ってそこにテキストファイルを一つ置いてください。
解答
hubの紹介のための問題でした。mkdir hoge && cd hoge && git init && echo aho > aho.txt
$ && git add -A && git commit -m "aho"
&& hub create ryuichiueda/hoge && git push origin master
Initialized empty Git repository in /home/ueda/hoge/hoge/hoge/.git/
master (root-commit) 76206c8] aho
[1 file changed, 1 insertion(+)
create mode 100644 aho.txt
Updating origin
created repository: ryuichiueda/hoge
Counting objects: 3, done.
Writing objects: 100% (3/3), 215 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:ryuichiueda/hoge.git
* [new branch] master -> master
Q5
次のファイルの1行目の複素数と2行目の複素数をかけ算してください。
cat complex
$ 1 + 4*i
3 - 2*i
解答
Perlを使ってみました。(Perlに慣れていればもっと前処理は簡単になると思います。)
cat complex | sed 's/^/(/' | sed 's/$/)/' | sed '2,$i*' |
$ xargs | tr -d ' ' |
xargs -I@ perl -e '{use Math::Complex;print(@);print "\\n"}'
11+10i
Q6
フィボナッチ数列で、6765の4つ前の数を出力してください。
解答
echo a | awk 'BEGIN{a=1;b=1}{while(1){print a;c=b;b+=a;a=c}}' |
$ grep -m 1 -B4 6765 | head -n 1
987
Q7
次の数字の列について、00, 01, 02,...,99の数字2つ並びのうち、含まれないものを抽出してください。できる人はループを使わないで抽出してください。
cat nums
1232154916829552629124634124821535923503018381369677458868876877570978993996890718096846698577281037379417474410221480004050608111920262721512985412925301
解答
seq -w 0 99 | while read n ; do grep -q $n nums || echo $n ; done
$ 31
33
42
43
56
61
64
65
whileやforを使わない場合はこんな感じで。
cat nums | sed 's/.\\(.*\\)/\\1\\n&/' | fold -b2 | grep .. | sort -u |
$ sort -m - <(seq -w 00 99) | sort | uniq -u
31
33
42
43
56
61
64
65
Q8
次のアルファベットの区間のうち、間に含まれるアルファベットが一番多いものはどれでしょうか。
cat alphabet
$ a-g
e-q
z-v
r-y
解答
ブレース展開を使うとこんな感じです。
cat alphabet |
$ awk '{a=$1;gsub(/-/,"..",a);print "echo",$1,"{"a"}"}' |
bash | awk '{print $1,NF}' | sort -k2,2n |
tail -n 1 | awk '{print $1}'
e-q
あとは10進数のasciiコードに変換する方法を示します。
cat alphabet | xxd -ps | fold -b2| tr a-f A-F |
$ sed '1iobase=10;ibase=16;' | bc | xargs -n 4 |
awk '{print $1-$3}' | tr -d - | awk '{print NR,$1}' |
sort -k2,2n | tail -n 1 | awk '{print $1}' |
xargs -I@ sed -n @p alphabet
e-q
cat alphabet | tr - ' ' |
$ perl -anle '{print abs(ord($F[0])-ord($F[1]))}' |
awk '{print NR,$1}' | sort -k2,2n | tail -n 1 |
awk '{print $1}' | xargs -I@ sed -n @p alphabet
e-q