シェル芸スパルタン演習(第19回シェル芸勉強会編)
ここ最近、Unixシェルに触る機会が減っており、CLIを使う能力の低下を感じていた。
また、近日中に、第25回シェル芸勉強会の開催が予定されており、参加するにあたり予習をしたいとも考えていた。
そこで、過去に開催されたシェル芸勉強会の問題を活用し、シェル芸力をつける演習をおこなうことにした。
今回は、問題として、第19回シェル芸勉強会の設問を用いた。
実行環境
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
xxd V1.10 27oct98
usp Personal Tukubai 20160402 ( Open usp Tukubaiで代用可能)
シェル芸演習
問題文は、以下のURLから。
https://blog.ueda.asia/?p=7146
模範解答は、こちらから。
https://blog.ueda.asia/?p=7068
問1
実行した環境によって出力を変更する問題。
端末上とインタプリタシェル上では、環境変数SHLVLの値が異なる事を利用した。
screenやtmux等の仮想端末を使っている場合は、SHLVLの値を調整しないと、うまく動かないかも。
01 #!/bin/sh
02
03 [ $SHLVL -eq 2 ] && echo '10ppm' || echo '40ppm'
以下、コピペ実行用のワンライナーコード。
[ $SHLVL -eq 2 ] && echo '10ppm' || echo '40ppm'
問2
自然数を、降順 → 昇順に出力する問題。
降順に出力するコマンドと、昇順に出力するコマンドを生成し、実行すればOK。
01 #!/bin/sh
02
03 echo 1 4 |
04 awk '{print "seq",$2,"-1",$1; print "seq",$1+1,$2}' |
05 sh
以下、コピペ実行用のワンライナーコード。
echo 1 4 | awk '{print "seq",$2,"-1",$1; print "seq",$1+1,$2}' | sh
問3
1234567890を含む13桁の数字を列挙する問題。
ひたすら地道に、全パターンを生成していく…
01 #!/bin/bash
02
03 yes '<(seq 0 9)' |
04 head -n 3 |
05 xargs |
06 sed 'p;p;p' |
07 sed '1s/.*/loopx <(echo 1234567890) &/; 2s/<(seq 0 9)/loopx & <(echo 1234567890)/1; 3s/\(<(seq 0 9)\) \1/loopx & <(echo 1234567890)/; 4s/.*/loopx & <(echo 1234567890)/' |
08 bash |
09 tr -d ' '
以下、コピペ実行用のワンライナーコード。
yes '<(seq 0 9)' | head -n 3 | xargs | sed 'p;p;p' | sed '1s/.*/loopx <(echo 1234567890) &/; 2s/<(seq 0 9)/loopx & <(echo 1234567890)/1; 3s/\(<(seq 0 9)\) \1/loopx & <(echo 1234567890)/; 4s/.*/loopx & <(echo 1234567890)/' | bash | tr -d ' '
問4
複数行にまたがった特定文字列を置換する問題。
sedにて、レコードを改行ではなく、Null文字で区切るオプション-zを使うのがポイント。
後は、正規表現で置換するだけ。
01 #!/bin/sh
02
03 cat Q4 |
04 sed -z 's/す\n*っ\n*と\n*こ\n*ど\n*っ\n*こ\n*い/朴念仁/g'
以下、コピペ実行用のワンライナーコード。
cat Q4 | sed -z 's/す\n*っ\n*と\n*こ\n*ど\n*っ\n*こ\n*い/朴念仁/g'
問5
会長のブログから、画像を抜き出す問題。
HTMLソースから"img src"を抜き出し、それを取得すれば良い。
ただし、目的の画像はbase64エンコーディングされているので、それをデコードする。
01 #!/bin/sh
02
03 curl -s 'https://blog.ueda.asia/?page_id=7123' |
04 grep 'img src=' |
05 grep base64 |
06 sed 's/.*img src=".*base64,\(.*\)"\/>.*/\1/' |
07 base64 -d > chinju.png
以下、コピペ実行用のワンライナーコード。
curl -s 'https://blog.ueda.asia/?page_id=7123' | grep 'img src=' | grep base64 | sed 's/.*img src=".*base64,\(.*\)"\/>.*/\1/' | base64 -d > chinju.png
問6
2進数のビット列を、日本語文に戻す問題。
bcで2進数から16進数に変換し、更にそれをxxdで文字列に変換、最後にnkfで文字エンコーディングを変換すればOK。
01 #!/bin/sh
02
03 cat Q6 |
04 sed 'iobase=16; ibase=2' |
05 awk 1 |
06 BC_LINE_LENGTH=0 bc |
07 xxd -r -p |
08 nkf -Lu
以下、コピペ実行用のワンライナーコード。
cat Q6 | sed 'iobase=16; ibase=2' | awk 1 | BC_LINE_LENGTH=0 bc | xxd -r -p | nkf -Lu
問7
SHLVLの値を100にする問題。
01 #!/bin/sh
02
03 SHLVL=100; echo $SHLVL
…嘘ですすいませんごめんなさいorz
気を取り直して、再度解答をば。
解答時のSHLVLは2であったので、それを100になるまでシェルを起動し最後にechoするコマンド列を生成を作る。
後はシェルに入力・実行させてやれば良い。
01 #!/bin/sh
02
03 yes 'bash' |
04 head -n 98 |
05 sed '$aecho $SHLVL' |
06 bash
以下、コピペ実行用のワンライナーコード。
yes 'bash' | head -n 98 | sed '$aecho $SHLVL' | bash
問8
危険シェル芸のfork爆弾を、何とかして途中で止める問題。
fork爆弾を実行する度に、ランダムな名前のファイルを生成し、カレントにあるファイル数が100になった時点で終了するようにする。
01 #!/bin/sh
02
03 : (){ touch $(cat /dev/urandom |tr -dc '[:alnum:]' |fold -w 64 |head -n 1) ; [ "$(ls |wc -l)" -gt 1000 ] && exit 0; : |: & }; :
以下、コピペ実行用のワンライナーコード。
: (){ touch $(cat /dev/urandom |tr -dc '[:alnum:]' |fold -w 64 |head -n 1) ; [ "$(ls |wc -l)" -gt 1000 ] && exit 0; : |: & }; :
雑記
にゃーーーーーん。
一番近い所まで来てくれました。ツシマヤマネコの隠れた魅力は、ネコ科の中でも随一のジト目だと思うんだ。 2016.09.14(水) #東山動物園 #ツシマヤマネコ りょう pic.twitter.com/Q7Uky6znMe
— ginjiro (@gin_135) 2016年9月16日