もはや初心者向けではなくなった「第30回シェル芸勉強会 大阪サテライト」の備忘録

イベント関連ページ

各会場の告知

レポート・まとめ(2017年 9月 1日現在)

午前の部

講師

  • 鳥海秀一(@hid_tori)さん/USP友の会

動画

資料

感想など

前回の「Perl の正規表現(仮題)」に続き、Perlの正規表現について学びました。

Perlコードの中で正規表現を書く時は、「m{regex}msx」や「s{regex}{replacement}msx」の決め打ちで済ましているので、マッチ演算子のデリミタに「'」や「?」を使うと挙動が変わることは知りませんでした。

このことだけでも十分にややこしいのですが、

  • マッチ演算子の戻り値について、スカラーコンテキストで評価する場合とリストコンテキストで評価した場合の違い
  • プログレッシブマッチ
  • Unicode属性およびUnicodeブロック属性
  • ルックアラウンドアサーション(先読み・後読み)
  • ……など

と知っておく項目がテトリスのブロックのごとく積み上がってくると、Perlの正規表現には闇しかないのではないかと思えてきます。

とりあえず、

$ perldoc perlreref
$ perldoc perluniprops

を読んで復習することにしますが、次回の学習内容は更に過酷になるようで今から戦々恐々です。

午後の部

動画

問題・模範解答

解答

A1: リポジトリからディレクトリ名とキーワードを抽出

$ grep -m1 'Keywords:' $(find . -name main.md | xargs) | sed 's/^.*posts\///;s/\/main.md:/ /' | sort
20170806_check_of_webhook Keywords: Webhook
20170810_negi Keywords: ネギ
20170810_negistagram Keywords: Twitter, Instagram, ネギ
20170812_working Keywords: 働けども働けども, bashcms2
20170814_layout Keywords: table, 雑
20170818_bash Keywords: 嫌がらせ
20170820_bootstrap Keywords: Bootstrap
20170820_injection Keywords: injection
template Keywords:

$(COMMAND)によるコマンド置換と、grepでマッチ回数が指定した回数になったら処理を打ち切る-mオプションを利用して解答しました。

手順としては、

  1. find . -name main.md | xargsで各記事のmain.mdへのパスを取得
  2. grep -m1 'Keywords:'で各記事のmain.mdごとに「Keywords:」にマッチする1つめの行を抽出
  3. sed 's/^.*posts\///;s/\/main.md:/ /'で不要部分を削除
  4. sortでソート

となっています。

A2: HTML内の相対パスを絶対パスに変換

$ sed -r 's%(href|src)="%\1="/files/%g;s%="/files/(https?:[^"]+")%="\1%g;s%="/files/\./%="/files/%g;s%="/files//%="/%g' url.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <ul>
    <li><a href="/files/hoge.html">ほげ</a></li>
    <li><img src="/files/ayasii.jpg" alt="怪しい" /></li>
    <li><a href="https://blog.ueda.tech/">クソブログ</a><a href="/files/huge.html">ふげ</a></li>
    <li><a href="/root.jpg"></a>これはそのまま</li>
    <li><a href="http://www.usptomo.com/">更新してない</a></li>
  </ul>
</body>
</html>

sedでゴリゴリと置換して解答しました。

手順としては、

  1. 全てのパスの先頭に「/files/」を追加
  2. パスが「/files/http:」および「/files/https:」になっている場合は「/files/」を削除
  3. パスが「/files/./」になっている場合は「./」を削除
  4. パスが「/files//」になっている場合は「/files/」を削除

となっています。

A3: Markdownコード片からHTTPヘッダ付きHTML5ドキュメントを生成

$ echo -e "Content-Type: text/html\n\n<!""DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n</head>\n<body>\n"$(markdown list)"\n</body>\n</html>" | sed 's/> </>\n</g'
Content-Type: text/html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<ul>
<li>妬み</li>
<li>嫉み</li>
<li>僻み</li>
</ul>
</body>
</html>

ファイルlistに対してmarkdownを適用した結果の前後に、必要な文字列を加えただけの解答です。

別解として、pandocを使った場合を紹介しておきます。

$ pandoc -s -t html5 list | sed '/generator/,/endif/d' | sed '1s#^#Content-Type: text/html\n\n#'
Content-Type: text/html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
<ul>
<li>妬み</li>
<li>嫉み</li>
<li>僻み</li>
</ul>
</body>
</html>

不要な文字列の削除と必要な文字列の追加をそれぞれsedで処理しています。

A4: GitHubにリポジトリを新規作成後、テキストファイルをプッシュ

GitHub用のCLIツール、hubをインストールしたところで時間切れになりました。

現時点ではあくまでもインストールしただけで使い方はほとんど分かっていないので、現時点では解答を見送っておくことにします。

遅くとも今年中には、今更ながら一からJavaScriptを学んでみようと思ってフレームワークやライブラリを一切使わずに作ったゲームをGitHub上で公開するつもりですので、少なくともその時までにhubの使い方を覚えておくことにします。

A5: 複素数の掛け算

$ cat complex | sed 's/i/I/g;s/.*/(&)/' | sed -z 's/\n/\*/' | gp -fq | sed 's/I/i/g'
11 + 10*i

計算機代数システムPARI/GPのgpで複素数の計算ができるので、それを利用します。

ただし、gpでは虚数単位を「i」ではなく「I」と大文字にしているため、その部分についてはsedで置換しておく必要があります。

A6: フィボナッチ数列で6765の4つ前の数を求める

$ seq 1 50 | xargs -I@ echo "echo 'fibonacci(@)' | gp -fq" | sh | grep -B4 '^6765$' | head -n1
987

ここでは、フィボナッチ数を得るためにgpfibonacci関数を使っています。

手順としては、

  1. seqで数字を1〜50まで生成
  2. xargs -I@(「@」にはseqで得られた数字が入る)で「echo 'fibonacci(@)' | gp -fq」という具合にgpで1〜50番目のフィボナッチ数を得るための文字列を生成
  3. 生成した文字列をshでコマンドとして実行
  4. 出力結果に対してgrep -B4 '^6765$'を適用し、「6765」にマッチする行から4行前までを抽出
  5. head -n1で最初の1行だけを出力

となっています。

A7: 与えられた数字の列について、00〜99の数字2つ並びのうち、含まれないものを抽出

$ diff <(cat <(fold -w2 nums) <(sed 's/^.//' nums | fold -w2) | grep '..' | sort -n | uniq) <(seq -w 0 99) | awk 'NF==2{print $2}'
31
33
42
43
56
61
64
65

基本的には、

  • 数字の列および、それをsed 's/^.//'で1つずらした数字の列を、それぞれfold -w2で1行につき数字2つにした後sort -nuniqで昇順に重複なく並べたもの
  • seq -w 0 99で生成した「00」から「99」までの2つ並びの数字

をプロセス置換経由でdiffしているだけです。

A8: 与えられたアルファベットの区間のうち、最も長いものを抽出

$ cat alphabet | perl -nlE '@a=split "-";@b=sort {$a cmp $b} @a;$s=join "-",@b;$s=~s/(.)-(.)/@c=($1..$2);say $_," ",@c," ",$#c+1/e' | sort -k3,3nr | awk 'NR==1{print $1}'
e-q

時間内に解けたものの、Perlの配列を示すsigilである「@」がTwitterのスクリーンネーム用の記号と重複するために解答の投稿は行いませんでした。

手順としては、

  1. perlで各行について
    1. -」をデリミタにして区間の開始文字と終了文字を配列@aに格納
    2. 開始文字と終了文字の順番が逆の場合を想定し、配列@aをソートした配列@bを生成
    3. -」をデリミタにして配列@bをスカラー変数$sに格納
    4. /e評価修飾子付きのs///演算子でスカラー変数$sから「開始文字-終了文字 対象区間内にある全ての文字 対象区間の長さ」を出力
  2. 第3フィールド(対象区間の長さ)で降順にsort
  3. awk 'NR==1{print $1}'で1行目の第1フィールド(開始文字-終了文字)を出力

となっています。

ちなみに、手順1での結果は

$ cat alphabet | perl -nlE '@a=split "-";@b=sort {$a cmp $b} @a;$s=join "-",@b;$s=~s/(.)-(.)/@c=($1..$2);say $_," ",@c," ",$#c+1/e'
a-g abcdefg 7
e-q efghijklmnopq 13
z-v vwxyz 5
r-y rstuvwxy 8

のように出力されます。

LT大会

動画

第30回シェル芸勉強会LT シェル芸思考

発表者: くんすと(@kunst1080)さん

  • (シェル芸で問題を解くときの)思考の順番
    1. コマンド一撃で終わらせられるかどうか考える
    2. 中間データの形式を設計する
    3. コマンドをシコシコ入力しながら答えに寄せていく

確かに言われてみれば、中間データの形式について意識するようになってからシェル芸勉強会での問題が解ける割合が上がったような気がします。

自分のA8の解説も、中間データの形が大事であることの一例になっているのではないかと思います。

FORK爆弾爆発中のロードアベレージを見る

発表者: MSR(@msr386)さん

  • FORK爆弾爆発中のロードアベレージをリアルタイムで見たい
    • uptimewtopは使えない
    • カーネルダンプも使えない
    • cgroupでリソース(CPU・メモリ等)を制限できる
  • cgroupで使用CPUコアとメモリ上限を設定
  • :(){ :|:& };:でデモ(暴発のおまけつき)

みんな大好きFORK爆弾のコーナーです。見方を変えれば、cgroupを使うと危険シェル芸の封じ込めができるということで、Linuxマシンのセキュリティの向上に役立ちそうな話でした。

破壊的難読化シェル芸

発表者: たいちょー(@xztaityozx_001)さん

  • 置換による難読化はあまりにも弱い
  • gunzipgzip
  • xxdに通して書けるように

Web上に転がっているコードを拾ってきて無闇に実行してはいけない、というのがよく理解できると思います。

試しに、自分も難読化シェル芸を一つばかり。

slの実行: $(echo 1f8b080068c0a75900032bcee10200aec26b8003000000 | xxd -p -r | gunzip -c)

……とりあえず、こんな感じでしょうか?

AWS API リクエストへの署名

発表者: so(@3socha)さん

  • AWS API リクエストについて
    • AWS CLI、各種 SDK は全て REST API を叩いている
    • API の仕様は公開されている
    • リクエストに Access Key と Secret Access Key を署名する必要がある
  • AWS API の署名プロセスをシェル芸で追いかける
    1. 署名バージョン 4 の正規リクエストを作成
    2. 署名バージョン 4 の署名文字列を作成
    3. AWS 署名バージョン 4 の署名を計算
    4. 署名情報をリクエストに追加する

署名バージョン 4 を使用して AWS リクエストに署名する - アマゾン ウェブ サービス」が何とシェル芸で実現できてしまうという話です。

それにしてもopenssl、サブコマンドもオプションも多すぎる……。

感想など

東京の本会場のイベント名から「初心者」という文字列が消えたことから分かるように、午前の部の講義内容がマニアックかつ難しく、講義が進むにつれて部屋が沈黙に包まれていったのが印象に残っています。

なお、午後の部の難度については前回と同じ程度で、「難しいけれど殺しにかかってくるという程ではない」というふうに感じました。

最後に、

に改めてお礼を申し上げます。ありがとうございました。

Written on September 1, 2017