ネギ焼きが大阪ローカルのマイナーな食べ物だと知った「第29回シェル芸勉強会 大阪サテライト」の記録

イベント関連ページ

各会場の告知

レポート・まとめ

午前の部

講師

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

動画

資料

感想など

シェル芸でawksedを使っていてどうしようもなくなった時の最後の手段、Perlワンライナーについての講義でした。

タイトルには正規表現とありますが、そこにたどり着くまでに知っておかなければならないことが多々ある、ということで正規表現の詳細については次回に持ち越しとなりました。

AWK以上に存在する特殊変数に、豊富な起動オプション、そして次回の講義で紹介されることのなる強力な正規表現……これらを使いこなせればかなりのシェル芸の向上が見込まれそうです。

あくまでも、使いこなせればの話ですが。

午後の部

動画

問題・模範解答

解答

A1: ファイルkadai1kadai2から全員の得点リストを作成

$ 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

まず、ファイルkadai1kadai2は次のようになっています。

$ 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 鳥海 欠出欠出欠出

ファイルattendattend6は次のようになっています。

$ 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ワンライナーの手順は

  1. 区切り文字の設定として、特殊変数$,に「 」をセット
  2. 第4フィールド(perlでは配列の添字は0からスタート)が空の場合は「0」を代入
  3. 第3フィールドの文字列に対して、指定文字(「」のみ、もしくは「」・「」のいずれか)にマッチした部分を空リスト()に代入し、これをscalar関数によってスカラーコンテキストで評価することでそれぞれのマッチ回数を求める
  4. 3. の方法で各受講者の出席率を求め、半分に満たなければ第4フィールドに「0」を代入
  5. 第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

残念ながら当日には解答できなかった問題です。

解き方としては、

  1. xargs -n1で1行につき数字1つのフォーマットに整形
  2. awkを使って各行の数字の文字列長をデータの第1フィールドとして行頭に追加
  3. 第2フィールド(数字)の値でsortする
  4. 第2フィールドを出力するが、第1フィールド(文字列長)の値が変わった場合、前に改行文字を付ける
  5. awkENDパターンでデータ末尾の改行を追加
  6. 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つずつ縦に並べたものと、seqfactorそして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フィールドについて欠番部分が「>」になります。

この後、

  1. awkで第1フィールドのみ抽出
  2. xargsで横1列に整列
  3. 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/&quot;/"/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文字参照「&#160;」を「 」に置換し、そして最後にsedで「&quot;」を「」に置換するという別解を示しておきます。

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

  1. 」を「_」に置換
  2. 任意の文字の後に「 」を付ける

という下準備をしてから、Tukubaiコマンドのtateyokoで行と列を縦横変換すると次のようになります。

$ cat shellgei | sed 's/ /_/g;s/./& /g' | tateyoko
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ m _ _ " _ _
_ " m _ _ m _ _
_ " _ " _ m _ _
(...略...)
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _

この出力をsedで「_ _ _ _ _ _ _ _」の行を削除した後、tateyokosedで再変換して解答を得ています。

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を入れ子状態で起動

端末が大量に分裂していく様子はあたかもライフゲームを観ているかのようです。

そして、おなじみ(?)うんこチャレンジも堂々の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)

  • convertpbmtoasciiで手書きSVGをアスキーアートに変換できることを利用したシェル芸2つを公開
    1. 流れる「うんこ💩」バナー
    2. 回転する「寿司🍣」バナー

スライドもバナー芸で済ませてしまいました……(とりあえずウケて良かった)。

感想など

LT大会後の、東京から遠征された ぐれさん(@grethlen)さん を囲んだ二次会での話題(素数を判別する正規表現)を含め、相変わらず栄養価の高い勉強会でした。

コンピューティング関連の生きた情報に接する機会に乏しい日々にあって、最前線で活躍するエキスパート達が集うこの勉強会の存在は私のような素人にとって非常にありがたく思います。

最後に、

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

Written on July 12, 2017