ネギ焼きが大阪ローカルのマイナーな食べ物だと知った「第29回シェル芸勉強会 大阪サテライト」の記録
イベント関連ページ
各会場の告知
レポート・まとめ
- 「第29回シェル芸勉強会 大阪サテライト」レポート - くんすとの備忘録
- 第29回シェル芸勉強会へ遠隔参加 - 日々之迷歩
- jus共催 第29回シェル芸勉強会 @さくらインターネットさん - Togetterまとめ
午前の部
講師
- 鳥海秀一(@hid_tori)さん/USP友の会
動画
資料
感想など
シェル芸でawk
やsed
を使っていてどうしようもなくなった時の最後の手段、Perlワンライナーについての講義でした。
タイトルには正規表現とありますが、そこにたどり着くまでに知っておかなければならないことが多々ある、ということで正規表現の詳細については次回に持ち越しとなりました。
AWK以上に存在する特殊変数に、豊富な起動オプション、そして次回の講義で紹介されることのなる強力な正規表現……これらを使いこなせればかなりのシェル芸の向上が見込まれそうです。
あくまでも、使いこなせればの話ですが。
午後の部
動画
問題・模範解答
解答
A1: ファイルkadai1
とkadai2
から全員の得点リストを作成
$ awk '{name[$1]=$2}FILENAME=="kadai1"{k1[$1]=$3}FILENAME=="kadai2"{k2[$1]=$3}END{for(id in name){print id,name[id],k1[id]+k2[id]}}' kadai[12] | sort -k1,1
001 山田 40
002 出川 30
003 上田 15
004 今泉 22
005 鳥海 88
まず、ファイルkadai1
とkadai2
は次のようになっています。
$ cat kadai1
001 山田 20
002 出川 30
005 鳥海 44
$ cat kadai2
001 山田 20
003 上田 15
004 今泉 22
005 鳥海 44
第1フィールド(ID番号)の値をキーとした、3つの連想配列
name
……第2フィールド(名前)k1
……第3フィールド(課題1の点数)k2
……第3フィールド(課題2の点数)
にそれぞれ値を代入していくのですが、第3フィールドの値をk1
およびk2
に適切に割り振るために、現在読み込んでいるファイル名を格納しているawk
の特殊変数FILENAME
を使っています。
また、END
パターンでの出力順はawk
にとって都合の良い順番でしかないため、awk
からの出力をsort -k1,1
でソートしています。
A2: ファイルattend6
のデータでファイルattend
に6回目の出欠を追加
$ join -j1 attend <(diff -y <(seq -w 005) <(grep -Po '\d{3}' attend6 | sort) | awk '{$2=$2=="<"?"欠":"出";print}') | sed -r 's/ (.)$/\1/'
001 山田 出出欠出出出
002 出川 出出欠欠欠欠
003 上田 出出出出出出
004 今泉 出出出出出欠
005 鳥海 欠出欠出欠出
ファイルattend
とattend6
は次のようになっています。
$ cat attend
001 山田 出出欠出出
002 出川 出出欠欠欠
003 上田 出出出出出
004 今泉 出出出出出
005 鳥海 欠出欠出欠
$ cat attend6
001,005,003
まず、attend6
から第1フィールドがID番号、第2フィールドが出欠となっているデータを生成します。
seq -w
で生成した連番と、attend6
のデータをgrep -Po '\d{3}'
で縦に並べてソートしたものをdiff -y
に与えると
$ diff -y <(seq -w 005) <(grep -Po '\d{3}' attend6 | sort)
001 001
002 <
003 003
004 <
005 005
という出力が得られるので、第2フィールドの文字列をawk
で「出」あるいは「欠」に置き換えると次のようになります。
$ diff -y <(seq -w 005) <(grep -Po '\d{3}' attend6 | sort) | awk '{$2=$2=="<"?"欠":"出";print}'
001 出
002 欠
003 出
004 欠
005 出
ファイルattend
のデータと、ここまでに説明したattend6
を加工したデータとをjoin -j1
でそれぞれの第1フィールドを使用して結合し、最後の不要な空白をsed
で削除しています。
A3: 出席が過半数に満たない人、テストを受けていない人を0点にする
$ join -j1 -a1 attend test | perl -alE '$,=" ";$F[3]=$F[3]?$F[3]:0;say $F[0],$F[1],scalar(()=$F[2]=~/出/g)/scalar(()=$F[2]=~/出|欠/g)<0.5?0:$F[3]'
001 山田 90
002 出川 0
003 上田 0
004 今泉 80
005 鳥海 0
指定したファイルそれぞれの第1フィールドで結合する-j1
と、1つめのファイルについて、2つめのファイルと対応する行が無くても出力する-a1
という2つのオプションを指定してjoin
すると出力は
$ join -j1 -a1 attend test
001 山田 出出欠出出 90
002 出川 出出欠欠欠 78
003 上田 出出出出出
004 今泉 出出出出出 80
005 鳥海 欠出欠出欠 93
となります。
この出力を、午前の部で学んだPerlワンライナーに与えます。なお、実行時に次のオプションを加えています。
-a
……AWKのように空白文字を区切りとして、各フィールドの値を配列@F
に格納-l
……行末の改行を自動的に処理-E
……1行のプログラムを指定して実行(feature
プラグマによる拡張付)
このPerlワンライナーの手順は
- 区切り文字の設定として、特殊変数
$,
に「 」をセット - 第4フィールド(
perl
では配列の添字は0からスタート)が空の場合は「0」を代入 - 第3フィールドの文字列に対して、指定文字(「出」のみ、もしくは「出」・「欠」のいずれか)にマッチした部分を空リスト
()
に代入し、これをscalar
関数によってスカラーコンテキストで評価することでそれぞれのマッチ回数を求める - 3. の方法で各受講者の出席率を求め、半分に満たなければ第4フィールドに「0」を代入
- 第1フィールド(ID番号)、第2フィールド(名前)、第4フィールド(修正後の点数)の順で出力
となっています。
A4.1: 同じ桁の数を横並びに正負を分けた状態で出力
$ echo -1 4 5 2 42 421 44 311 -9 -11 | xargs -n1 | awk '{print length($1),$1}' | sort -k2,2n | awk '{printf $1!=c?"\n"$2:" "$2;c=$1}END{printf "\n"}' | tail -n+2
-11
-9 -1
2 4 5
42 44
311 421
残念ながら当日には解答できなかった問題です。
解き方としては、
xargs -n1
で1行につき数字1つのフォーマットに整形awk
を使って各行の数字の文字列長をデータの第1フィールドとして行頭に追加- 第2フィールド(数字)の値で
sort
する - 第2フィールドを出力するが、第1フィールド(文字列長)の値が変わった場合、前に改行文字を付ける
awk
のEND
パターンでデータ末尾の改行を追加tail -n+2
でデータ冒頭の空白行を削除
となっています。
A4.2: 同じ桁の数を横並びに正負を分けた状態で出力(一部「+」記号あり)
$ echo -1 +4 5 2 42 421 44 311 -9 -11 | xargs -n1 | awk '{print length($1),$1}' | sort -k2,2g | awk '{if($2~/^+/)--$1;printf $1!=c?"\n"$2:" "$2;c=$1}END{printf "\n"}' | tail -n+2
-11
-9 -1
2 +4 5
42 44
311 421
この問題も当日には解答できませんでした。
基本的にはA4.1と同じ解き方ですが、「+」記号に対応するため
sort
の箇所で-k2,2n
ではなく-k,2,2g
にオプションを変更- その次の
awk
で数字の先頭に「+」がある場合、文字列長を1減らす
という変更を加えています。
なお、sort
の-n
および-g
オプションの意味は次の通りです。
-n, –numeric-sort
文字列を数値とみなして比較する
-g, –general-numeric-sort
一般的な数値として比較を行う
A5: ファイルtriangle
の内容を右回転させる
$ cat triangle
1
3 9
7 a 6
8 4 2 5
$ cat triangle | xargs | awk '{printf " "$7"\n "$8" "$4"\n "$9" "$5" "$2"\n"$10" "$6" "$3" "$1"\n"}'
8
4 7
2 a 3
5 6 9 1
ファイルの内容を一旦xargs
で1行に整形してから、awk
で地道に出力位置を置き換えていくという方法しか思い浮かびませんでした。
A6: 1から100までの素数が不完全に揃ったファイルfactor
について、欠番で改行して出力
$ diff -y <(cat prime | xargs -n1) <(seq 100 | factor | awk 'NF==2{print $2}') | awk '{print $1}' | xargs | sed -r 's/(> )+/\n/g'
2 3 5 7 11 13 17 19
31 37 41 43 47 53 59
67 71 73 79 83 89 97
ファイルprime
の内容を1つずつ縦に並べたものと、seq
とfactor
そしてawk
で求めた100までの素数をdiff -y
に与えると
$ diff -y <(cat prime | xargs -n1) <(seq 100 | factor | awk 'NF==2{print $2}')
2 2
3 3
5 5
(...略...)
19 19
> 23
> 29
31 31
(...略...)
59 59
> 61
67 67
(...略...)
83 83
89 89
97 97
というふうに、第1フィールドについて欠番部分が「>」になります。
この後、
awk
で第1フィールドのみ抽出xargs
で横1列に整列sed
で1個以上の「>」を改行文字(「\n」)に置換
しています。
A7: アスキーアート文字のHTMLを標準出力に出力
$ cat ./nyaan.html | w3m -T text/html -dump
"m mmm "m
m" "" m"" m m m"
# mm#m"#"m "" "" m#m
# m # "m mm" m" # m
"# """" # m" "mm"
w3m
で-T
オプションで文書のタイプを指定して表示すればOKですが、それだけではいささか寂しいので
$ cat ./nyaan.html | sed '/^<span/,/<br \/>/!d' | sed 's/<[^>]\+>//g' | nkf --numchar-input | sed 's/"/"/g'
"m mmm "m
m" "" m"" m m m"
# mm#m"#"m "" "" m#m
# m # "m mm" m" # m
"# """" # m" "mm"
ファイルnyaan.html
内で<span>
で始まる行をsed
で抽出し、nkf --numchar-input
でUnicode文字参照「 」を「 」に置換し、そして最後にsed
で「"」を「“」に置換するという別解を示しておきます。
A8: アスキーアート文字の文字間隔を狭める
$ cat shellgei | sed 's/ /_/g;s/./& /g' | tateyoko | sed -r '/^_( _)+$/d' | tateyoko | sed 's/ //g;s/_/ /g'
m
""m m "m # # # #
mm # # #mmm""" m"
" m" mmm"" # # # m" # mm""m
m" #mm m" # m" " # #
"mm"" """" "m" #" m" #
まず、ファイルshellgei
内のデータについてsed
で
- 「 」を「_」に置換
- 任意の文字の後に「 」を付ける
という下準備をしてから、Tukubaiコマンドのtateyoko
で行と列を縦横変換すると次のようになります。
$ cat shellgei | sed 's/ /_/g;s/./& /g' | tateyoko
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ m _ _ " _ _
_ " m _ _ m _ _
_ " _ " _ m _ _
(...略...)
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
この出力をsed
で「_ _ _ _ _ _ _ _」の行を削除した後、tateyoko
とsed
で再変換して解答を得ています。
LT大会
動画
sortコマンドのマルチコア対応状況について調べてみた
発表者: いとす(@itosue)さん
- 様々な環境下での
sort
コマンドのスピードを計測 - 使用コア数が多ければ良いというものでもない(4ヶがBest)
sort
で高速化といえば冒頭にLANG=C
を付ける程度しか知らなかったのですが、
–parallel=N
同時に実行するソートの数を N に変更する
というオプションを利用する方法もあるということを初めて知りました。処理スピードにこだわってシェルスクリプトを書く際に役立つかもしれません。
みんなで!Base64難読化シェル芸
発表者: たいちょー(@xztaityozx_001)さん
- いかにして危険シェル芸を隠蔽するか
- Base64を使って日本語文字列からコマンド列を取り出す
- ヒント: 「ず」は「a」
flagが危険シェル芸になっているCryptoといえば分かる人には分かるかもしれません。
あと、むやみに難読化シェル芸を他人に送信して実行させるのは慎みましょう。
シェル芸で使いたくてLINQが使えるコマンドを作ったらawkでよかった話
発表者: たいちょー(@xztaityozx_001)さん
- 「ShelLINQ」の紹介
- 福岡のアイドルグループのことではなく、.NET Frameworkの統合言語クエリ(Language INtegrated Query)をシェル上で使えるようにしたもの
- C#のソースを生成→
mcs
でビルド→mono
で実行 - 型推論あり
- 残念ながら
awk
よりは遅い
Windows上でしか出来なかったPowerシェル芸がBash上で出来てしまうという、面白い逸品です。
異なった環境下でも自分の手になじんだツールと同じ操作で作業できるのは、便利さだけではなく作業ミスを減らす上でも重要だと思います。
狂気!端末細胞分裂!
発表者: ぐれさん(@grethlen)さん
- 「xpanes」の紹介
tmux
のウィンドウを大量に分割- 複数のホストやDockerコンテナに接続して作業できる
xpanes
でウィンドウを4分割→4分割……- TMUX環境変数を空にして
tmux
を入れ子状態で起動
- TMUX環境変数を空にして
端末が大量に分裂していく様子はあたかもライフゲームを観ているかのようです。
そして、おなじみ(?)うんこチャレンジも堂々の25ウインドウにて披露されました(yes 'shuf -e う こ ん' | head -n 25 | xpanes -I@ -c '@'
)。
AWS Windows のパスワード
発表者: so(@3socha)さん
- AWS Windowsインスタンス起動時のパスワードを取得する際は、ローカルのRSA秘密鍵をブラウザ上のAWSマネジメントコンソールに送信する
- 秘密鍵そのものが送信されるわけではないが、精神衛生上あまりよろしくない
- コマンドが使えるならシェル芸で
CLIに日頃から親しんでいれば、GUIよりも自分の意図や行動をより良く把握できるということで、シェル芸がQOLを向上させる良い例のLTだと思います。
画像シェル芸入門
発表者: 小原一哉(@KoharaKazuya)さん
imgcat
でiTerm2のターミナルに画像を表示できるssh
の接続先でも使える- ImageMagickやGraphvizなどのツールにパイプで渡せる
- 画像でもシェル芸
このLTもまた、シェル芸がQOLを高める良い例です。
従来の画像シェル芸の場合、すぐに編集結果を確認できないという問題があるのですが、この手法だと安心して画像シェル芸に勤しめることでしょう。
帰ってきたバナー芸+手書きSVG
発表者: 日柳光久(@mikkun_jp)
convert
とpbmtoascii
で手書きSVGをアスキーアートに変換できることを利用したシェル芸2つを公開- 流れる「うんこ💩」バナー
- 回転する「寿司🍣」バナー
スライドもバナー芸で済ませてしまいました……(とりあえずウケて良かった)。
感想など
LT大会後の、東京から遠征された ぐれさん(@grethlen)さん を囲んだ二次会での話題(素数を判別する正規表現)を含め、相変わらず栄養価の高い勉強会でした。
コンピューティング関連の生きた情報に接する機会に乏しい日々にあって、最前線で活躍するエキスパート達が集うこの勉強会の存在は私のような素人にとって非常にありがたく思います。
最後に、
- 大阪サテライトの主催をされている、くんすと(@kunst1080)さん、so(@3socha)さん
- 大阪サテライト会場を提供してくださっている、フェンリル株式会社 大阪本社様
- 鳥海秀一(@hid_tori)さん、上田隆一(@ryuichiueda)さんをはじめとする、メイン会場の講師およびスタッフの皆さん
に改めてお礼を申し上げます。ありがとうございました。