シェル芸スパルタン演習(第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
usp Personal Tukubai 20160402 ( Open usp Tukubaiで代用可能)
シェル芸演習
問題文および模範解答は、以下の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 我々はシェル芸人だ。
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パーサなんて無くても、フィルタコマンドを使えば、いくらでも自由に加工が出来るのが、シェル芸の強みだと思う。
今回の問題を応用すれば、エロ画像収集が捗るね!