2016年10月26日

シェル芸スパルタン演習(第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


シェル芸演習

問題文は、以下の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; : |: & }; :

雑記

  • にゃーーーーーん。

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