「第31回シェル芸勉強会 大阪サテライト」の記録

イベント関連ページ

各会場の告知

レポート・まとめ

勉強会本編

動画

問題・模範解答

解答

A1: 「1」の直前にある数字を削除(改行は無視)

問題用ファイルnum.txtの内容は次の通りです。

$ cat num.txt
1214235325231
325316321345
135326547361
414353515325

sedのオプション

-r, –regexp-extended
    スクリプトで拡張正規表現を使用する
-z, –null-data
    NUL 文字で行を分割する

を使い、改行文字「\n」が0ヶまたは1ヶの後に「1」が来るパターンの直前にある文字を1ヶ削除します。

$ cat num.txt | sed -rz 's/.(\n?1)/\1/g'
11423532521
325163134
13532654731
1435315325

なお、当日(10月7日)の解答ではsedの部分がsed -rz 's/\n/_/g;s/.(_?1)/\1/g;s/_/\n/g'となっていましたが、改行文字「\n」を「_」に置換する必要はありませんでした。

A2: インデントの無い行を、上の行のインデントに合わせる

問題用ファイルindent.txtの内容は次の通りです。

$ cat indent.txt
  * aa
* bbb
         * cccccc
* ddd
      * eeeeeeeeee
* fff
   * gggg
* hhh

偶数行のインデントを奇数行のそれに合わせれば良いということで、まずは奇数行と偶数行をpasteで横に並べます。

$ paste <(sed '1~2!d' indent.txt) <(sed '2~2!d' indent.txt)
  * aa  * bbb
         * cccccc       * ddd
      * eeeeeeeeee      * fff
   * gggg       * hhh

そして、sedで1ヶ目の「*」から2ヶ目の「*」までを削除し、偶数行のデータにインデントを施します。

$ paste <(sed '1~2!d' indent.txt) <(sed '2~2!d' indent.txt) | sed 's/\*[^*]\+//'
  * bbb
         * ddd
      * fff
   * hhh

最後に、インデントを施した偶数行のデータの前に奇数行のデータを挿入するために、デリミタに改行文字「\n」を指定してpasteを実行します。

$ paste -d '\n' <(sed '1~2!d' indent.txt) <(paste <(sed '1~2!d' indent.txt) <(sed '2~2!d' indent.txt) | sed 's/\*[^*]\+//')
  * aa
  * bbb
         * cccccc
         * ddd
      * eeeeeeeeee
      * fff
   * gggg
   * hhh

A3: 素数アスキーアート

まず、seqで1から20まで1行ずつ出力し、行の値が素数の場合にはその値に応じて「*」を出力します。

$ seq 20 | factor | awk '{n=NF==2?$2:0;for(i=0;i<n;i++)printf "*";printf "\n"}'

**
***

*****

*******



***********

*************



*****************

*******************
 

そして、値が素数の行について末尾の「*」を「@」に置換した後、全ての行に必要なだけ「*」を追記します。

$ seq 20 | factor | awk '{n=NF==2?$2:0;for(i=0;i<n;i++)printf "*";printf "\n"}' | sed 's/\*$/@/;s/$/********************/;s/^\(.\{20\}\).*/\1/'
********************
*@******************
**@*****************
********************
****@***************
********************
******@*************
********************
********************
********************
**********@*********
********************
************@*******
********************
********************
********************
****************@***
********************
******************@*
********************

A4: ASCIIコードだけで「おはようございます」

$ echo e3818ae381afe38288e38186e38194e38196e38184e381bee381990a | xxd -p -r
おはようございます
$ echo 44GK44Gv44KI44GG44GU44GW44GE44G+44GZCg== | base64 -d
おはようございます

xxdbase64を使えばOKです。

A5: 最小公倍数

$ echo 'lcm(3,4)' | gp -fq
12

計算機代数システムPARI/GPのlcm関数で最小公倍数を求めることができます。

A6: 「あいうえお」から「ぁぃぅぇぉ」を出力

$ echo あいうえお | xxd -p | fold -w6 | sed '$d' | perl -nlE 'printf "%x",hex($_)-1' | xxd -p -r; echo
ぁぃぅぇぉ

「あいうえお」および「ぁぃぅぇぉ」のUTF-8文字コードは

$ paste <(echo あいうえおぁぃぅぇぉ | grep -o .) <(echo あいうえおぁぃぅぇぉ | tr -d '\n' | xxd -p | fold -w6)
あ      e38182
い      e38184
う      e38186
え      e38188
お      e3818a
ぁ      e38181
ぃ      e38183
ぅ      e38185
ぇ      e38187
ぉ      e38189

のようになっているため、解答するには文字コードの数値をそれぞれ1減らすことができるワンライナーを考えればよい、ということになります。

大まかな手順としては

  1. xxd -p | fold -w6 | sed '$d'で文字コードに変換
  2. perl -nlE 'printf "%x",hex($_)-1'で文字コードの数値をそれぞれ1減らす
  3. xxd -p -r; echoで文字として出力

となっています。

A7: △がせり上がるアニメーションを生成

$ for i in {0..10}; do echo $i | perl -nlE 'if($_){say " "x(10-$_)."/"." "x($_*2-1)."\\"}else{say " "x(10-$_)."^"}'; C=$(($C+1)); sleep 1; done
          ^
         / \
        /   \
       /     \
      /       \
     /         \
    /           \
   /             \
  /               \
 /                 \
/                   \

forループで0から10を引数として、引数の値によって半角スペースの数を調整して出力するPerlワンライナーを1秒ごとに実行しています。

A8: 全角5文字で折り返し

$ cat sd.txt | tr ' ' '_' | grep -o . | LANG=C awk '{print length($1),$1}' | awk '{len=$1==1?len+=0.5:len+=1;if(len<5){printf $2}else{print $2;len=$1==1?0.5:0}}' | tr '_' ' '
Software D
esignの「
シェル芸人
からの挑戦
状」は絶好
調なんです
が、もうち
ょっとTwit
terで読ん
だ感想を述
べていただ
ければと。

非常に難しい問題でしたので、宿題として解いてみました。

まず、1文字あたりのバイト数を確認するワンライナー

$ cat sd.txt | tr ' ' '_' | grep -o . | LANG=C awk '{print length($1),$1}'
1 S
1 o
1 f
1 t
1 w
(...略...)
3 け
3 れ
3 ば
3 と
3 。

を実行すると、半角文字は1バイト、全角文字は3バイトであることが分かります。

この出力に対して

  1. 出力すべき行について、文字列の長さとして半角文字であれば0.5を、全角文字であれば1を加える
  2. 文字列の長さが5未満の場合は、第2フィールドの文字をそのまま出力
  3. 文字列の長さが5に達した場合は、第2フィールドの文字に改行を加えて出力
  4. 3.で出力する時の文字が半角文字である場合は、「5文字で合わない時は4.5文字で折り返す」ルールに従い、次行の文字列の長さを0.5から始める

という処理を施すと所定の出力を得ることができ、この処理を実装している部分がawk '{len=$1==1?len+=0.5:len+=1;if(len<5){printf $2}else{print $2;len=$1==1?0.5:0}}'となっています。

A9: 周期表のCSVファイルを作成

$ curl -s https://ja.wikipedia.org/wiki/%E5%91%A8%E6%9C%9F%E8%A1%A8 | sed '/id="周期表"/,/<\/center>/!d' | sed 's/<table /&border="1" /' | w3m -dump -T text/html | sed '/[A-Z]/!d' | sed 's/│/,/g;s/ //g;s/^,//;s/,$//;s/://' | sed 's/Ba,/&L/;s/Ra,/&A/;s/,La/L&/;s/,Ac/A&/' > PeriodicTable.csv
$ cat PeriodicTable.csv
H,,,,,,,,,,,,,,,,,He
Li,Be,,,,,,,,,,,B,C,N,O,F,Ne
Na,Mg,,,,,,,,,,,Al,Si,P,S,Cl,Ar
K,Ca,Sc,Ti,V,Cr,Mn,Fe,Co,Ni,Cu,Zn,Ga,Ge,As,Se,Br,Kr
Rb,Sr,Y,Zr,Nb,Mo,Tc,Ru,Rh,Pd,Ag,Cd,In,Sn,Sb,Te,I,Xe
Cs,Ba,L,Hf,Ta,W,Re,Os,Ir,Pt,Au,Hg,Tl,Pb,Bi,Po,At,Rn
Fr,Ra,A,Rf,Db,Sg,Bh,Hs,Mt,Ds,Rg,Cn,Nh,Fl,Mc,Lv,Ts,Og
L,La,Ce,Pr,Nd,Pm,Sm,Eu,Gd,Tb,Dy,Ho,Er,Tm,Yb,Lu
A,Ac,Th,Pa,U,Np,Pu,Am,Cm,Bk,Cf,Es,Fm,Md,No,Lr

この問題も、宿題として解いてみました。

端的にいうと、sedの力技によるWebスクレイピングです。

LT大会

動画

rmコマンドチキンレース!

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

カスタマイズしたrmコマンドを使い、仮想マシンをジェンガに見立てて遊んでみようというLTです。

ただ遊ぶというだけでなく、どのファイルやディレクトリを削除するとシステムが壊れるのかを学ぶこともできます。

JavaScript製シューティングゲームをフルスクラッチで作ってみた

発表者: 日柳 光久(@mikkun_jp)

拙作のシューティングゲーム「EVADE AND DESTROY」の紹介です。

スマートフォンの片手持ちで遊べますので、暇つぶしにどうぞ。

ダブルシンク難読化シェル芸

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

危険シェル芸をハフマン符号化して難読化を試みるというLTです。

なお、ここで使われているエンコード/デコード用コマンド「shellhuffman」はシェルスクリプトで書かれています。

サイゼリヤで学ぶシェル芸

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

$ echo ヤサイゼリ | grep -o . | shuf -r | head -5 | tr -d '\n'
ヤイゼヤサ

このワンライナーを何回実行すると「サイゼリヤ」と出力されるのかを計算する際に見舞われたトラブルとその解決法についてのLTです。

大きなデータを扱うシェル芸を実行する際には、SIGPIPEの発生に気を付けたいものです。

sed ‘s/.*/sed計算機/’

発表者: いるやん(@Iruyan_Zak)さん

数値の計算が本来できないはずのsedで足し算を行ってしまうという力作のワンライナーです。

$ echo '(+ 5 7)' | sed -E 's/\(\+ ([0-9]) ([0-9])\)/\1\2/;y/123456789/abcdefghi/;s/.$/\U&/;tadd;:add;s/(.)X/1\10/;s/(.?)0(.?)/\L\1\2/;tendadd;y/abcdefghiABCDEFGHI/0abcdefghBCDEFGHIX/;badd;:endadd;y/abcdefghi/123456789/'
12

……この発想は無かった。

感想など

タイトルに「朝からだと疲れるから午後からでええじゃろ」とは銘打たれていましたが、やはり疲れました。

LT大会については、参加人数8名に対しLT発表者が5名という活況ぶりで内容の方もあらゆる意味でスゴく、充実した時間を過ごすことができました。

20回くらいシェル芸勉強会で鍛えると、素人でもフルスクラッチでブラウザゲームを作り上げることができる程度にはなるということで(ありがたや > ALL)。

最後に、

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

Written on October 19, 2017