読者です 読者をやめる 読者になる 読者になる

日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です

第25回シェル芸勉強会へ遠隔参加

awk Mac Shell シェル芸

色々と忙しい状況ではあったが、第25回シェル芸勉強会の福岡サテライト会場が開催出来た。開始時間が早くなったが会場はベータソフト様会議室を準備していただいた。大変感謝である。今回の参加者は9名だった。山を越えた県外からの参加者もいらっしゃった。朝から夕方までかなり喋ったので喉がガラガラになったのであった。

イベント案内ページ

本家東京会場

usptomo.doorkeeper.jp

大阪サテライト

atnd.org

福岡サテライト

atnd.org

大阪サテライトの開催レポートはこちら。今回もLTがすごいことに。

kunst1080.hatenablog.com

開始前

まずはみんなで自己紹介をした後、下記のスライドでイントロのお話をした。先日お仕事用の液晶ディスプレイを新調したばかりなのだが、1週間後に新機種が発表されて複雑な気持ちが否めない今日この頃。

午前の部

気を取り直して午前の部を開始した。今回は初心者の方が多いというのもあり、福岡サテライトは独自に進めることにした。Apache HTTP Severのログファイルを扱いながら、awkgrepcutsortuniqなどの使い方を説明。簡単な集計の方法へと話を進めるスタイルを試した。ネタとしては下記のページを参考にさせていただいた。うまく伝わっただろうか??

qiita.com

Apacheのログファイルは、上田会長のページで公開されているシェル芸勉強用データを利用させていただいた。

シェル芸練習用データ集 – 上田ブログ

お昼は餃子の王将へ食事に出かけた。大量の餃子もみんなで喰らえば怖くない!!というスタンス。

午後の部

午後からはいよいよ本番だ。今回の問題はパズル系だったが、難易度は幅広く内容も重要なことが多かった気がする。 問題と解答のページは、上田さんブログの記事を参照してもらいたい。

【問題と解答】第25回もう4年もやってんのかシェル芸勉強会 – 上田ブログ

ではここからは福岡サテライト会場でで考えた解答と説明の例をあげていく。問題が解けることよりも解説と考え方の説明を重視。解答例はMacで作成。GNU版のコマンドはguniqなど頭にgが付くコマンドになっている場合がある。

Q1

digpingなどのコマンド出力を文字列処理。grepのオプションやawktrの使い方な問題。

$ dig www.usptomo.com | grep -A1 ';; ANSWER SECTION:' | grep -v ';; ANSWER SECTION:' | awk '{print $NF}'
157.7.203.188

$ ping -c 1 www.usptomo.com | head -n 1 | awk '{print $3}' | tr -dc '0-9.'
157.7.203.188

Q2

awkNRを利用して階段状の出力を作ってみる。

$ yes ひらけ!ポンキッキ | head -n 9 | awk '{for(i=1;i<NR;i++){printf "#"}printf $0$0;print ""}'
ひらけ!ポンキッキひらけ!ポンキッキ
#ひらけ!ポンキッキひらけ!ポンキッキ
##ひらけ!ポンキッキひらけ!ポンキッキ
###ひらけ!ポンキッキひらけ!ポンキッキ
####ひらけ!ポンキッキひらけ!ポンキッキ
#####ひらけ!ポンキッキひらけ!ポンキッキ
######ひらけ!ポンキッキひらけ!ポンキッキ
#######ひらけ!ポンキッキひらけ!ポンキッキ
########ひらけ!ポンキッキひらけ!ポンキッキ

後は上下ひっくり返し、固定長で文字列を切り出して完成。

$ yes ひらけ!ポンキッキ | head -n 9 | awk '{for(i=1;i<NR;i++){printf "#"}printf $0$0;print ""}' | tail -r | cut -c 9-17
ひらけ!ポンキッキ
らけ!ポンキッキひ
け!ポンキッキひら
!ポンキッキひらけ
ポンキッキひらけ!
ンキッキひらけ!ポ
キッキひらけ!ポン
ッキひらけ!ポンキ
キひらけ!ポンキッ

Linuxの場合は最後の2つのコマンドを下記のように変更しよう。

  • tail -rtacへ変更
  • cut -c9-17awk {print substr($1,9,9)}へ変更(GNU cutコマンドはマルチバイト非対応)
###Linux用解答###
$ yes ひらけ!ポンキッキ | head -n 9 | awk '{for(i=1;i&lt;NR;i++){printf "#"}printf $0$0;print ""}' | tac | awk '{print substr($1,9,9)}'

Q3

teeを使うことしか思いつかなかった。@ebanさんの下記の解答例が面白くて、福岡会場で取り上げて説明をした。UNIXの入出力は全てファイルとして扱うことが出来るという素敵な例。

Q4

ギブアップ!上田会長の解答例を参考にした。

Q5

ちょっと難しく考えすぎたかもしれないが、下記の解答例を考えて解説した。まずはsleepを使ったコマンド列を作っておく。キャリッジリターンを使って改行させない指定がポイント。

$ yes | head | awk '{for(i=1;i<=NR;i++){printf "*"}print ""}' | sed "s/^/printf '/" | sed "s/$/\\\\r'; sleep 1/"
printf '*\r'; sleep 1
printf '**\r'; sleep 1
printf '***\r'; sleep 1
printf '****\r'; sleep 1
printf '*****\r'; sleep 1
printf '******\r'; sleep 1
printf '*******\r'; sleep 1
printf '********\r'; sleep 1
printf '*********\r'; sleep 1
printf '**********\r'; sleep 1

事前に上記の連続コマンドを作成し、シェルに渡して実行する例として解説した。

$ yes | head | awk '{for(i=1;i<=NR;i++){printf "*"}print ""}' | sed "s/^/printf '/" | sed "s/$/\\\\r'; sleep 1/" | sh
**********

Q6

内容はおそらく16進数ダンプだと思いそのままデコード、fileコマンドに渡したが謎。

$ echo b730a730eb30b8820a00 | xxd -p -r | file -
/dev/stdin: Non-ISO extended-ASCII text

最後をよく見ると0a00とある。0aは改行コードの16進ダンプ。改行が最後になってないので不自然である。ということで2文字つまり1バイトずつ入れ替えている?と推測。fileコマンドで確認して見たがよくわからず。2文字ずつ区切って入れ替える処理や、fileコマンドでの確認について詳しく解説をした。後は会長の解答通りnkfコマンドで。

$ echo b730a730eb30b8820a00 | fold -w 2 | xargs -n 2 | awk '{print $2,$1}' | xargs | tr -d ' ' | xxd -p -r | file -
/dev/stdin: data

Q7

秒毎に繰り返しを実行するやり方を考えてもらった。dateコマンドはGNU版を利用。最初に解説した解答例は下記の通りで、dateコマンドを86400回繰り返すやり方。

$ seq 0 86399 | while read n; do gdate -d "2016-10-29 00:00:00 $n sec" '+%s'; done
$ for n in {0..86399}; do gdate -d "2016-10-29 00:00:00 $n sec" '+%s'; done
$ seq 0 86399 | xargs -I@ gdate -d '2016-10-29 00:00:00 @ sec' '+%s'
$ seq 0 86399 | sed "s/^/gdate -d '2016-10-29 00:00:00 /" | sed "s/$/ sec' '+%s'/" | sh

次にdateコマンドのフィルタモードで高速処理する方法を説明した。

$ seq 0 86399 | sed -e "s/^/2016-10-29 00:00:00 /" -e "s/$/ sec/" | gdate -f - '+%s'

素数のみを出力するのは、いつものシェル芸的方法で。あ、最後にUNIX時間から元に戻すのを忘れていた。

$ seq 0 86399 | sed -e "s/^/2016-10-29 00:00:00 /" -e "s/$/ sec/" | gdate -f - '+%s' | gfactor | awk 'NF==2{print $2}'

Q8

福岡では難易度と時間の都合上省いた。後で考えた解答がこちら。上田会長の解答例を少し変えて、後半の行列入替をawkで頑張っただけ。

$ seq 1 50 | awk '{a=sin($1/3) * 10 + 10;for(i=0;i<a;i++)printf "-";printf "+";for(i=a;i<20;i++)printf "-";print ""}' | awk '{for(i=1;i<=NF;i++)a[NR,i]=$i}END{for(j=1;j<=NF;j++){for(i=1;i<=NR;i++){printf a[i,j]}print ""}}' FS= | tail -r | tr '+-' '* '
                                                  
   ***                **                 **       
  *                  *  *               *  *      
      *                                           
 *                  *    *             *    *     
                                                  
       *                  *           *           
*                  *                         *    
                                                  
        *                            *            
                  *        *                  *   
                                                  
         *                                        
                 *          *       *          *  
                                                  
                                                  
          *     *            *     *            * 
                                                  
           *                  *   *               
               *                                 *
            ***                ***                
                                                  

行列入替は下記の記事で書いたものを流用。

papiro.hatenablog.jp

終了後

もう一度全体を通して復習をしながら説明した。福岡の解答例はATNDイベントページのコメントに貼り付けて共有すればいいね!ということに気がついた。

今回も解説重視でひたすらしゃべった感じだ。わかりやすい説明はどうすればいいか、毎回悩みながらのベシャリである。シェルに親しむ楽しさ、コンピュータに頑張ってもらうためのヒントなどが伝わってるといいなあ。今回は喉がかなりガラガラになったのであった。問題作成と解説の上田会長、運営や会場管理者の方々、参加者の皆様、今回もありがとうお疲れ様。