もはや初心者向けではなくなった「第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
オプションを利用して解答しました。
手順としては、
find . -name main.md | xargs
で各記事のmain.md
へのパスを取得grep -m1 'Keywords:'
で各記事のmain.md
ごとに「Keywords:」にマッチする1つめの行を抽出sed 's/^.*posts\///;s/\/main.md:/ /'
で不要部分を削除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
でゴリゴリと置換して解答しました。
手順としては、
- 全てのパスの先頭に「/files/」を追加
- パスが「/files/http:」および「/files/https:」になっている場合は「/files/」を削除
- パスが「/files/./」になっている場合は「./」を削除
- パスが「/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
ここでは、フィボナッチ数を得るためにgp
のfibonacci
関数を使っています。
手順としては、
seq
で数字を1〜50まで生成xargs -I@
(「@」にはseq
で得られた数字が入る)で「echo 'fibonacci(@)' | gp -fq
」という具合にgp
で1〜50番目のフィボナッチ数を得るための文字列を生成- 生成した文字列を
sh
でコマンドとして実行 - 出力結果に対して
grep -B4 '^6765$'
を適用し、「6765」にマッチする行から4行前までを抽出 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 -n
とuniq
で昇順に重複なく並べたもの 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のスクリーンネーム用の記号と重複するために解答の投稿は行いませんでした。
手順としては、
perl
で各行について- 「-」をデリミタにして区間の開始文字と終了文字を配列
@a
に格納 - 開始文字と終了文字の順番が逆の場合を想定し、配列
@a
をソートした配列@b
を生成 - 「-」をデリミタにして配列
@b
をスカラー変数$s
に格納 /e
評価修飾子付きのs///
演算子でスカラー変数$s
から「開始文字-終了文字 対象区間内にある全ての文字 対象区間の長さ」を出力
- 「-」をデリミタにして区間の開始文字と終了文字を配列
- 第3フィールド(対象区間の長さ)で降順に
sort
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)さん
- (シェル芸で問題を解くときの)思考の順番
- コマンド一撃で終わらせられるかどうか考える
- 中間データの形式を設計する
- コマンドをシコシコ入力しながら答えに寄せていく
確かに言われてみれば、中間データの形式について意識するようになってからシェル芸勉強会での問題が解ける割合が上がったような気がします。
自分のA8の解説も、中間データの形が大事であることの一例になっているのではないかと思います。
FORK爆弾爆発中のロードアベレージを見る
発表者: MSR(@msr386)さん
- FORK爆弾爆発中のロードアベレージをリアルタイムで見たい
uptime
・w
・top
は使えない- カーネルダンプも使えない
cgroup
でリソース(CPU・メモリ等)を制限できる
cgroup
で使用CPUコアとメモリ上限を設定:(){ :|:& };:
でデモ(暴発のおまけつき)
みんな大好きFORK爆弾のコーナーです。見方を変えれば、cgroup
を使うと危険シェル芸の封じ込めができるということで、Linuxマシンのセキュリティの向上に役立ちそうな話でした。
破壊的難読化シェル芸
発表者: たいちょー(@xztaityozx_001)さん
- 置換による難読化はあまりにも弱い
gunzip
とgzip
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 の署名プロセスをシェル芸で追いかける
- 署名バージョン 4 の正規リクエストを作成
- 署名バージョン 4 の署名文字列を作成
- AWS 署名バージョン 4 の署名を計算
- 署名情報をリクエストに追加する
「署名バージョン 4 を使用して AWS リクエストに署名する - アマゾン ウェブ サービス」が何とシェル芸で実現できてしまうという話です。
それにしてもopenssl
、サブコマンドもオプションも多すぎる……。
感想など
東京の本会場のイベント名から「初心者」という文字列が消えたことから分かるように、午前の部の講義内容がマニアックかつ難しく、講義が進むにつれて部屋が沈黙に包まれていったのが印象に残っています。
なお、午後の部の難度については前回と同じ程度で、「難しいけれど殺しにかかってくるという程ではない」というふうに感じました。
最後に、
- 大阪サテライトの主催をされている、くんすと(@kunst1080)さん、so(@3socha)さん、はやつ~(@haya2_)さん
- 大阪サテライト会場を提供してくださっている、さくらインターネット株式会社 大阪本社様
- 鳥海秀一(@hid_tori)さん、上田隆一(@ryuichiueda)さんをはじめとする、メイン会場の講師およびスタッフの皆さん
に改めてお礼を申し上げます。ありがとうございました。