【問題と解答】jus共催 第30回危念シェル芸勉強会

Sat Aug 26 15:52:53 JST 2017 (modified: Sun Oct 1 10:50:27 JST 2017)
views: 3216, keywords:コマンド,CLI,Linux,シェル芸,シェル芸勉強会 この記事は最終更新日が6年以上前のものです。

問題のみのページはこちら

問題で使うファイル等

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
ノート   このエントリーをはてなブックマークに追加 
 

prev:【問題のみ】jus共催 第30回危念シェル芸勉強会 next:jus共催 第30回危念シェル芸勉強会の報告

やり散らかし一覧

記事いろいろ