シェル芸160本ノック解答例 その16

技術評論社から出版された『1日1問、半年以内に習得 シェル・ワンライナー160本ノック』の解答例です。


問題151

$ curl -s https://file.ueda.tech/eki/p/13.xml | grep -B1 山手線 | grep -Po '\d+' | xargs -I@ curl -s https://file.ueda.tech/eki/l/@.xml | grep -A2 station_name | sed 's/^[^<]*//;s/<[^>]*>//g' | xargs -n3 | awk '{printf "printf \047%s \047; curl -s \047https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=%s&lat=%s&outtype=JSON\047 \174 jq .elevation; sleep 1;\n",$1,$2,$3}' | sh | sort -k2,2n
有楽町 2.8
高輪ゲートウェイ 3.1
品川 3.1
御徒町 3.3
田町 3.4
新橋 3.6
東京 3.6
秋葉原 3.8
大崎 3.8
五反田 3.9
浜松町 4.3
神田 4.6
田端 6
日暮里 6.3
鶯谷 8.9
上野 11.3
西日暮里 12.4
渋谷 15.5
駒込 16.6
大塚 19.1
恵比寿 20.4
巣鴨 21.9
高田馬場 22.3
目白 25
原宿 28.4
目黒 29.7
池袋 32.5
代々木 34.9
新大久保 35
新宿 37.5

問題152

あらかじめpython3 -m http.server 8080で即席Webサーバを立てておきます。

# 即席Webサーバを止めると`Warning`が出力される
$ while :; do sleep 5; curl -sI http://localhost:8080/ |& head -n1 | grep -q ' 200 ' && echo Success || echo Warning; done
Success
Warning
Success
(...略...)

問題153

$ (printf 'HEAD / HTTP/1.1\nHost: www.google.co.jp\n\n'; sleep 1) | telnet www.google.co.jp 80
Trying 2404:6800:400a:813::2003...
Connected to www.google.co.jp.
Escape character is '^]'.
HTTP/1.1 200 OK
Content-Type: text/html; charset=Shift_JIS
(...略...)
Set-Cookie: NID=511=NwUbb2VszSbFHk-HIyo7-jVmMK_3O0TUTDsCW2vTbcyNLpBNoljmUQyofVK5ZSuzLmTeSYwuiu7mFOs5hr07SjTdDU0crEhcCeu1Id0Q1SvgATqg1GI50kGHjVkXieaq47TS1AE7JlC2XBdV3LB6XqiS1VLHgVMo7MthAPrgOKg; expires=Fri, 16-Jun-2023 07:00:56 GMT; path=/; domain=.google.co.jp; HttpOnly

Connection closed by foreign host.

HTTPSの場合は、telnetの代わりにopenssl s_clientを使います。

$ (printf 'HEAD / HTTP/1.1\nHost: www.google.co.jp\n\n'; sleep 1) | openssl s_client -connect www.google.co.jp:443 -quiet -no_ign_eof
depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1
verify return:1
depth=1 C = US, O = Google Trust Services LLC, CN = GTS CA 1C3
verify return:1
depth=0 CN = *.google.co.jp
verify return:1
HTTP/1.1 200 OK
Content-Type: text/html; charset=Shift_JIS
(...略...)
Set-Cookie: NID=511=kjAu-js059PGQsuT-5il998QG2g-vtMXFOXMKDbHHC4v3cLm1gC0ueX7iMQDUIvhZF13LY0_R_W1PFRIr4MzA1OqquLIFWPJPd9rRVTQXhgHtQ8SVaj2fk6bGaJZIeRFkB8PVkv4BgGxCYnrgta3a4KLFYF81NKg0c83YlOibkY; expires=Fri, 16-Jun-2023 07:57:50 GMT; path=/; domain=.google.co.jp; HttpOnly
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

DONE

問題154

$ for c in {curl,'wget -qO-',dig,nslookup,'ping -c1'}; do (sudo strace -f $c www.example.com >/dev/null) |& grep -q '/etc/hosts' && (echo $c | sed 's/ .*//'); done
curl
wget
ping

問題155

$ while :; do printf 'HTTP/1.1 200 OK\nContent-Length: 4\n\ntest' | nc -l -p 8080; [ $? -ne 0 ] && break; done
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.74.0
Accept: */*

別の端末からcurlして、レスポンスが受け取れるか確認をします。

$ curl http://localhost:8080
test

不正なContent-Lengthで実行する場合、curlが正常終了できるようnc-q <秒数>オプションを付ける必要があります。

$ while :; do printf 'HTTP/1.1 200 OK\nContent-Length: 5\n\ntest' | nc -q 1 -l -p 8080; [ $? -ne 0 ] && break; done
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.74.0
Accept: */*

再度、別の端末からcurlして、レスポンスが受け取れるか確認をします。

$ curl http://localhost:8080
curl: (18) transfer closed with 1 bytes remaining to read
test

「1バイト読み残して転送を終了」という警告が出ています。


問題156

$ for d in $(cat domains.txt); do printf "$d "; dig $d | sed '/^;; ANSWER/,/^;; Query/!d' | grep -P '(\d{1,3}\.){3}\d{1,3}$' | wc -l; done | awk '$2>1{print $1}'
gihyo.jp

なお、表示されているFQDNは、2022年12月21日現在のものです。


問題157

問題157小問1

$ sudo tcpdump -nx -c 1 icmp 2>/dev/null
13:31:08.233401 IP 192.168.1.10 > 104.22.59.251: ICMP echo request, id 54703, seq 1, length 64
        0x0000:  4500 0054 f73e 4000 4001 dda6 c0a8 010a
        0x0010:  6816 3bfb 0800 7c7b d5af 0001 8cdd a363
        0x0020:  878f 0300 0809 0a0b 0c0d 0e0f 1011 1213
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
        0x0050:  3435 3637

なお、表示されているpingの送信内容は一例です。

問題157小問2

$ sudo tcpdump -nx -c 1 icmp 2>/dev/null | awk '$1~/^0x/{$1="";printf $0}' | sed -E 's/.* 0800( [0-9a-f]{4}){2} 0001 (.*)/\2\n/'
ddeb a363 39c0 0a00 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637

なお、表示されているICMPエコー要求メッセージのデータフィールドは一例です。


問題158

問題158小問1

$ ping -4 gihyo.jp | (grep -Po -m1 'ttl=\d+' && pkill -u $USER ping) | sed 's/.*=//'
57

なお、表示されているTTLの値は一例です。

問題158小問2

$ sudo traceroute -4 -I gihyo.jp 2>/dev/null | tail -n1 | awk '{print $1-1}'
7

なお、経由ノード数はネットワーク環境により異なります。


問題159

$ time cat sites.txt | xargs -L1 -P0 host -tA -R0 -W0 -4 | awk '/not found:/{print $2}' > fake_sites.txt

real    0m0.966s
user    0m0.548s
sys     0m0.338s

# 存在しないドメインを確認
$ cat fake_sites.txt
taobao.come
rarirure.ro
yandex.runrun

問題160

$ openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -noout -dates
notBefore=Mar 14 00:00:00 2022 GMT
notAfter=Mar 14 23:59:59 2023 GMT

なお、表示されているサーバ証明書の有効期間は、2022年12月24日現在のものです。


完走した感想

160問すべてを完走した感想ですが、日付や時刻の取り扱いや疑似ファイルシステムの利用、そしてgitのサブコマンド群の使い方など、今まである程度シェル芸に触れてきたにもかかわらず決して明るいとは言えない分野の知識が得られて良かったです。また、本来文字列の操作が中心であるシェル上でバイナリデータを取り扱うのも意外性があって楽しめました。

シェル芸というものは、PCではなく自分の脳にインストールするタイプのソフトウェアのような何かであるのかもしれません(そしてアンインストールする方法/必要はおそらく、ない)。

それでは、最後に。執筆陣のみなさん、どうもありがとうございました。

Written on December 29, 2022