2016年10月11日

シェル芸スパルタン演習(第04回シェル芸勉強会編)

ここ最近、Unixシェルに触る機会が減っており、CLIを使う能力の低下を感じていた。
また、近日中に、第25回シェル芸勉強会の開催が予定されており、参加するにあたり予習をしたいとも考えていた。
そこで、過去に開催されたシェル芸勉強会の問題を活用し、シェル芸力をつける演習をおこなうことにした。

今回は、問題として、第04回シェル芸勉強会の設問を用いた。


実行環境

  • 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

  • nkf 2.1.4

  • curl 7.50.3


シェル芸演習

問題文および模範解答は、以下のURLから。
http://www.slideshare.net/ryuichiueda/20130406-18763665

問1

[問題1:肩ならし]

次のファイルから、「index.cgi」を除去してください。
ただし、p=index.cgi は残すこと。

$ cat 2.html
<a ref="http://my.favorite.jk/index.cgi#jk">会長のブログ</a>
<a ref="http://index_cgi.com/index.cgi?p=index.cgi">aho</a>

HTMLソースの整形。
sedのsコマンドを使い、"index.cgi"のみを除去する。
"p=index.cgi"を除外するために、正規表現には"/index.cgi"を指定した。

01 #!/bin/sh
02
03 cat 2.html     |
04 sed 's;/index[.]cgi;/;g'

以下、コピペ実行用のワンライナーコード。

cat 2.html | sed 's;/index[.]cgi;/;g'

問2

[問題2:urlのリスティング]

次のファイルを作って、urlを抜き出してください。

$ cat 1.html
<a href="http://www.aho.com">
アホどっと混む
</a>
<a href="#top">トップへ</a>
<a href="http://www.jk.jp">"JK"</a>

HTMLソースから、URLを抜き出す問題。
各種フィルタコマンドを使い、少しずつ切り出してく。

01 #!/bin/sh
02
03 cat 1.html                          |
04 grep href                           |
05 sed 's/<a href="\(.*\)">.*/\1/'     |
06 grep 'https\{0,1\}'

以下、コピペ実行用のワンライナーコード。

cat 1.html | grep href | sed 's/<a href="\(.*\)">.*/\1/' | grep 'https\{0,1\}'

問3

[問題3:整形]

以下のインデントの汚いhtmlを整形してください。
一行にtd一個にすること。

$ cat 3.html
<table>
        <tr>
<td>a</td><td>b</td>
<td>c</td>
        </tr>
</table>

お行儀の悪いHTMLソースを整形する問題。
一旦、インデント・改行を全て削除した後、改めてインデント・改行をおこなうのがポイント。

01 #!/bin/sh
02
03 cat 3.html                       |
04 tr -d ' \n'                      |
05 xargs                            |
06 sed 's;</table>;\n&;'            |
07 sed 's;</\{0,1\}tr>;\n\t&;g'     |
08 sed 's;<td>;\n\t\t&;g'

以下、コピペ実行用のワンライナーコード。

cat 3.html | tr -d ' \n' | xargs | sed 's;</table>;\n&;' | sed 's;</\{0,1\}tr>;\n\t&;g' | sed 's;<td>;\n\t\t&;g'

問4

[問題4:webページの切り取り]

yahooさんのトップページ(http://www.yahoo.co.jp)からトピックスの見出しを抽出しましょう。

2016-10-04T10:27:58現在、yahooのトップページには、トピックスの見出しは存在しない。
そのため、代わりとしてニュースの見出しを抽出することにする。

Webページ(HTMLソース)から、特定の部分を抽出する問題。
僕が解いた時点では、Yahooのトップページにはトピックスの見出しが無かったので、代わりにニュースの見出しを使った。
grep、sedで、地道に削りだしていく。

01 #!/bin/sh
02
03 curl -s 'http://www.yahoo.co.jp'     |
04 grep '<strong>ニュース</strong>' |
05 sed 's;<a href=;\n&;g' |
06 sed 's;<img src=;\n&;g' |
07 grep pickup |
08 sed 's;</a>.*;;' |
09 sed 's;<a href=.*>;;'

以下、コピペ実行用のワンライナーコード。

curl -s 'http://www.yahoo.co.jp' | grep '<strong>ニュース</strong>' | sed 's;<a href=;\n&;g' | sed 's;<img src=;\n&;g' | grep pickup | sed 's;</a>.*;;' | sed 's;<a href=.*>;;'

問5

[問題5:数値参照の変換]

次のような数値参照、実体参照文字列を読めるように変換してください。

$ cat numref
&#25105;&#12293;&#12399;&#12471;&#12455;&#12523;&#33464;&#20154;&#12384;&#12290;

Unicodeの文字コード位置指定の値を、指定している値・文字に変換する問題。
nkfに、ずばり求めるオプション—​numchar-inputがあるので、それを利用するだけ。

01 #!/bin/sh
02
03 cat numref     |
04 nkf --numchar-input

以下、コピペ実行用のワンライナーコード。

cat numref | nkf --numchar-input

問6

[問題6:ポスト]

http://www.usptomo.com/TOMONOKAI_CMS/CGI/hoge.cgi に、ポストでデータを送りつけてください。

残念ながら、現在(2016-10-28T12:51:09)時点では、上記のURLは存在しない…​
なので、各自ローカルにWebサーバを建てるなりして、実行してください。
解答は、単純にcurlのPOSTリクエストをおこなうオプション、--dataで、データを送りつけるだけ。

01 #!/bin/sh
02
03 curl --data a=unko 'localhost/hoge.cgi'

以下、コピペ実行用のワンライナーコード。

curl --data a=unko 'localhost/hoge.cgi'

問7

[問題7:データの収集]

本日の最高気温をワンライナーで出力してください。

適当なWebサイトから取得して、最高気温部分を削りだすだけ。
今回は、気象庁の天気予報ページを使った。
grep、tr、sed等で、何なりと。

01 #!/bin/sh
02
03 curl -s 'http://www.jma.go.jp/jp/yoho/329.html'     |
04 grep -A 32 -E '今日[123]?[0-9]日'                   |
05 grep -E 'class="(city|max)"'                        |
06 tr -d '\n'                                          |
07 sed 's/度/&\n/g'                                    |
08 sed 's;<[^<]*>; ;g'

以下、コピペ実行用のワンライナーコード。

curl -s 'http://www.jma.go.jp/jp/yoho/329.html' | grep -A 32 -E '今日[123]?[0-9]日' | grep -E 'class="(city|max)"' | tr -d '\n' | sed 's/度/&\n/g' | sed 's;<[^<]*>; ;g'

問8

[問題8:画像をダウンロード]

ウェブページに掲載されている画像を集めてください。
(yahooのニュースページ等から)

Webページから、 エロ 画像を収集する問題。
HTMLソースから"img src="のターゲット先を抽出し、wgetすればOK。

01 #!/bin/sh
02
03 curl -s http://www.yahoo.co.jp/     |
04 grep -o 'img src="[^ ]*"'           |
05 awk -F\" '$0=$2'                    |
06 xargs wget -q

以下、コピペ実行用のワンライナーコード。

curl -s http://www.yahoo.co.jp/ | grep -o 'img src="[^ ]*"' | awk -F\" '$0=$2' | xargs wget -q

問9

[問題9:クローリング]

どこかのサイトのトップページにあるリンク先のリストを作って、リストのページや画像等をダウンロードしてください。
- 相対パスにも対応しましょう
- できたら再帰的にクローリング

前問の応用編。
相対パスになっているリンクに、ベースURLを付加して、wget -rする。

01 #!/bin/sh
02
03 curl -s --insecure 'https://www.usptomo.com/'                                     |
04 grep 'href'                                                                       |
05 sed -n '/href="\{0,1\}\//p; /href="\{0,1\}https\{0,1\}:\/\/www.usptomo.com/p'     |
06 sed 's;.*href=\("\{0,1\}[^< ]*"\{0,1\}\)[^<]*>.*;\1;g'                            |
07 tr -d '"'                                                                         |
08 sed '/https\{0,1\}:\/\/www.usptomo.com/!s;^;https://www.usptomo.com;'             |
09 xargs wget -r --no-check-certificate

以下、コピペ実行用のワンライナーコード。
再帰的にクロールする関係で、相手のWebサイトに大きな負担を掛ける可能性がある点に注意。

curl -s --insecure 'https://www.usptomo.com/' | grep 'href' | sed -n '/href="\{0,1\}\//p; /href="\{0,1\}https\{0,1\}:\/\/www.usptomo.com/p' | sed 's;.*href=\("\{0,1\}[^< ]*"\{0,1\}\)[^<]*>.*;\1;g' | tr -d '"' | sed '/https\{0,1\}:\/\/www.usptomo.com/!s;^;https://www.usptomo.com;' #| xargs wget -r --no-check-certificate # 最後のコメントを外す際は、注意すること

雑記

  • HTMLがテーマの回。

  • HTMLパーサなんて無くても、フィルタコマンドを使えば、いくらでも自由に加工が出来るのが、シェル芸の強みだと思う。

  • 今回の問題を応用すれば、エロ画像収集が捗るね!

Tags: シェル芸 Unix
このエントリーをはてなブックマークに追加