ビル・ゲイツも知ってる!?
            シェルスクリプトでLinuxを
             256倍使いこなそう!!

                          USP友の会 上田隆一



2011年7月2日       第二回 LINUX女子部勉強会
contents
●   -1. USP友の会の紹介
●   0. 自己紹介
●   1. Linux使いの嗜み、シェルスクリプト
●   2. awkをシェルスクリプトで使い倒す
    ●   (一部、ユニケージの話)
●   3. まとめ



2011年7月2日       第二回 LINUX女子部勉強会   2
-1. USP友の会
●   シェルスクリプト(CUI)のコミュニティー
     ●   USP: universal shell programming
●   会員数:もうすぐ200人(200人目に粗品贈呈)
●   会の綱領
     ●   「酒は呑め呑め呑むならば(嘘)」
     ●   「本物の技術・本物の人」

                                            派手なウェブサイト




    2011年7月2日             第二回 LINUX女子部勉強会
                                            雑誌:USPマガジン   3
遊びにきてね
●   イベント
    ●   8月2日(火):定例会@東京湾納涼船
    ●   8月13日(土):某イベントでUSPマガジンを売る
        –   東京ビッグサイト 東2ホール S-53b
    ●   8月末:勉強会
    ●   9月22日(木):Tech LION vol. 3


●   ネット・メディア
    ●   Twitter @usptomo(残念な駄洒落のみ)
    ●   Facebook 「USP友の会」(イベント等の告知)
2011年7月2日               第二回 LINUX女子部勉強会   4
0. 自己紹介
●   上田隆一
    ●   1978年生まれ33歳
    ●   博士(工学)
        –   学位論文:State-Action Map Compression by using Vector
            Quantization for Decision Making of Autonomous Robots
    ●   26歳~30歳:東大で常勤の助手→助教
        –   新人賞のようなものをぽちぽち受賞
        –   教科書の翻訳(確率ロボティクス)
    ●   31歳:やりたいことに能力がついていかず、大学を辞める
        –   USP研究所のやっていることが面白くて入社


2011年7月2日                   第二回 LINUX女子部勉強会                         5
興味・野望
●   シェルスクリプト, CUI一行野郎
    ●   もともとwindowsで研究のプログラムを書いていたので新鮮


●   (仮称)次世代アナログコンピュータの構想
    ●   ポテンシャル場やベクトル場等をO(1)で計算する何か
        –   非言語型の人工知能が実現 → 世の中ひっくり返る
    ●   はやく10億円貯めて、物理と化学を勉強して研究にとりかかりたい
        –   貯金に1000年、研究に30年


●   カミさんの機嫌をとる手法の研究
●   娘を真人間にする方法
2011年7月2日              第二回 LINUX女子部勉強会   6
1. Linux使いの嗜み、シェルスクリプト
●   UNIXの生い立ち
●   テキストはユニバーサルなフォーマット




2011年7月2日       第二回 LINUX女子部勉強会   7
UNIXの生い立ち
●   誕生:1969年

●   UNIXが乗った最初の計算機
    ●   DEC PDP-7(1965年発売)
                                              PDP-7 (wikipediaより引用)
    ●   メモリ:9kB~144kB
        –   http://www.linfo.org/pdp-7.html




2011年7月2日                   第二回 LINUX女子部勉強会                           8
UNIXのテキスト文化
●   UNIX(Linux)は、文字で設定を行う
    ●   例:




●   文字はメモリを食う
    ●   on/offの設定:ゼロイチだと1bit、「on」「off」だと最大24bitで24倍
        –   バイナリ: 1
        –   文字(ASCIIコード): 11011110110011001100110
    ●   PDP-7では深刻な問題になりうる
●   なぜ、文字を選んだ???
2011年7月2日                     第二回 LINUX女子部勉強会         9
テキストは便利
●    CUIしか無かった:人間が設定を書きやすい。
     ●   今はGUIがあるが、それでも文字の設定ファイルを利用
     ●   ↑単なるレガシーなのか??


●    コマンド+パイプ
     ●   何でもcat, grep, moreで確認
     ●   バイナリファイル:専用のエディタが必要
         –   バグ・無理な拡張の巣窟、プログラムが肥大

    2011年7月2日          第二回 LINUX女子部勉強会   10
バイナリは(儲かるかもしれないが本質的には)面倒
●   例えば、専用バイナリ形式のワープロソフトを考える
    ●   そのワープロ専用の機能がたくさん
        –   文字列検索・置換機能、文字数カウント機能、スペルチェッカー、
            画像埋め込み機能・・・
    ●   アプリケーション1個に対して機能がO(n)個

●   TeXを考える
    ●   テキストファイルをdviにできればそれでよい。
    ●   アプリケーション1個に対して機能はO(1)個

2011年7月2日           第二回 LINUX女子部勉強会      11
偉い人も、言っている
●   UNIX哲学 [Gancarz2001]
    ●   小さいものは美しい。
    ●   各プログラムが一つのことをうまくやるようにせよ。
    ●   できる限り原型(プロトタイプ)を作れ。
    ●   効率よりも移植しやすさを選べ。
    ●   単純なテキストファイルにデータを格納せよ。
    ●   ソフトウェアの効率をきみの優位さとして利用せよ。
    ●   効率と移植性を高めるためにシェルスクリプトを利用せよ。
    ●   束縛するインターフェースは作るな。
    ●   全てのプログラムはフィルタとして振る舞うようにせよ。
2011年7月2日          第二回 LINUX女子部勉強会    12
時代はテキスト
●   事例1:バイナリ形式のテキスト化
    ●   Office 2007
        –   データ形式:zipで圧縮されたxml
    ●   理由
        –   バイナリフォーマットはソフト屋に抱え込まれるという世論
        –   計算機が強力になった
        –   バイナリ形式がややこしすぎて管理できなくなった?
●   事例2:サービスのweb化
    ●   HTTPは文字でデータをやりとり
2011年7月2日              第二回 LINUX女子部勉強会    13
これからのものはテキスト主流
●   最近の注目:Sphinx
    ●   ドキュメント作成ツール
        –   ReST(reStructuredText)形式というテキストで作文
        –   webページ、pdf、ePub等様々な形式に変換してくれる
        –   機能拡張に大きな可能性


●   今後の(勝手な)予想
    ●   ppmやpgmをgzip圧縮した画像が主流に?
    ●   ムービーファイルのテキスト化!(時刻、座標、rgbの羅列)

                      ・・・だってわかりやすい方がいいじゃないですか。
2011年7月2日               第二回 LINUX女子部勉強会          14
・・・ということで
●   Linuxをいじるならば、コマンドを使った
    テキスト処理に強くなろう!

    ●   UNIX系OS使いのタシナミ
    ●   UNIX系OS使いの基礎体力
        –   もしかしたら今日の内容は直接役に立たないかもしれませんが、
            端末をいじるあらゆる局面でじわじわ効いてきます。




2011年7月2日           第二回 LINUX女子部勉強会    15
2. awkをシェルスクリプトで使い倒す
●   ログなどの処理に便利なコマンド
●   awkをパイプでつなげてシェルスクリプトを書くと、
    かなりの種類の処理が可能になる。




2011年7月2日    第二回 LINUX女子部勉強会    16
awk
●   古いスクリプト言語
●   開発陣
    ●   Alfred Aho(ベル研→コロンビア大教授)
        –   著書:コンパイラ—原理・技法・ツール
    ●   Peter Weinberger(ベル研→google)
    ●   Brian Kernighan(ベル研→プリンストン大教授)
        –   著書:プログラミング言語C


●   言語なんですが、コマンドのように使います。
2011年7月2日            第二回 LINUX女子部勉強会     17
とりあえず使ってみる
●   こんなファイル(hogeという名前)
        a 100
        b 20
        c -10.4
●   コマンドを打つ
    ●   cat hoge | awk '{print $1}'
    ●   cat hoge | awk '$1=="b"'
    ●   cat hoge | awk 'BEGIN{a=0}{a+=$2}END{print a}'

2011年7月2日                第二回 LINUX女子部勉強会                 18
awkの挙動
●   いかにもUNIX的(フィールド指向)
    ●   空白で区切った表を標準入力で読み取る
    ●   文字列を割って$1, $2, $3, ...という変数に入れる
●   「データはこの様に持て」というメッセージ?

●   後はユーザの組んだ一行プログラムでいかようにも
    ●   検索、計算、文字列処理・・・


2011年7月2日          第二回 LINUX女子部勉強会        19
お題A:表計算をやってみましょう
●   注意:コードを追わず、何ができるかだけ、ぼんやり
    覚えてください。コードを追うと撃沈します。
●   ファイル(hoge)
             1 2 3
            0.1 0.2 0.3
             -1 -2 -3
●   横に足す
    ●   $ cat hoge | awk '{print $1,$2,$3,$1+$2+$3}'
            1236
            0.1 0.2 0.3 0.6
            -1 -2 -3 -6
2011年7月2日                     第二回 LINUX女子部勉強会          20
●   $0に、一行すべての文字列が入っている
    ●   $ cat hoge | awk '{print $0,$1+$2+$3}'
              1 2 36
            0.1 0.2 0.3 0.6
             -1 -2 -3 -6
●   変数も使えます
    ●   $ cat hoge | awk '{sum=$1+$2+$3;print $0,sum}'
              1 2 36
            0.1 0.2 0.3 0.6
             -1 -2 -3 -6
2011年7月2日                     第二回 LINUX女子部勉強会            21
●   書式を整える
    ●   $ cat hoge | awk '{sum=$1+$2+$3;print $0,
        sprintf("%10s",sum)}'
           1 2 3         6
          0.1 0.2 0.3   0.6
           -1 -2 -3      -6
●   面倒なのでfor文で
    ●   $ cat hoge | awk '{$4=$1+$2+$3;for(i=1;i<=4;i++)
        {printf("%5s",$i)};printf("n")}'
           1    2 3 6
          0.1 0.2 0.3 0.6
           -1 -2 -3 -6
2011年7月2日                     第二回 LINUX女子部勉強会              22
●   ややこしくなったらパイプで処理を分ける
    ●   $ cat hoge | awk '{print $0,$1+$2+$3}' |
        awk '{for(i=1;i<=4;i++){printf("%5s",$i)};printf("n")}'
             1    2 3 6
            0.1 0.2 0.3 0.6
             -1 -2 -3 -6




2011年7月2日                 第二回 LINUX女子部勉強会                          23
●   縦にも足してみましょう
    ●   $ cat hoge | awk '{print $0,$1+$2+$3}' | awk
        '{for(i=1;i<=4;i++){a[i]+=$i};print}END{print
        a[1],a[2],a[3],a[4]}' | awk '{for(i=1;i<=NF;i++)
        {printf("%5s",$i)};printf("n")}'
              1 2 3 6
            0.1 0.2 0.3 0.6
             -1 -2 -3 -6
            0.1 0.2 0.3 0.6
    ●   さすがに読み返せない。どうするか?

2011年7月2日                 第二回 LINUX女子部勉強会                  24
シェルスクリプトにする
●   基本、手で打つコマンドラインを
    ファイルに書いただけのもの
●   便利な点
    ●   保存できる        #!/bin/bash
                     #hoge.sh
    ●   コメントを書ける
                     cat hoge                                 |
                     #$1~$3: 数値
                     #各レコードの値を足して後ろにくっつける
                     awk '{print $0,$1+$2+$3}'                    |
処理を細かく区切って
                     #$1~$3:数値 $4:合計値
データのレイアウトだけ          #各フィールドの数値を足して最終行に出力
書いておけば、コードが          awk '{for(i=1;i<=4;i++){a[i]+=$i};print}
読みにくくても困らない。              END{print a[1],a[2],a[3],a[4]}'

2011年7月2日          第二回 LINUX女子部勉強会                                25
お題B:出力にこだわる
●   ところで、出力がCUI上というのは寂しい。
    ●   いや、寂しくないが、需要が多い。


●   テキストの出力は貧弱?
    ●   テキストだから何にでも化けるだろう。




2011年7月2日       第二回 LINUX女子部勉強会   26
●   csv
    ●   $ ./hoge.sh | awk '{print $1,$2,$3,$4}' | tr ' ' ','
             1,2,3,6
             0.1,0.2,0.3,0.6
             -1,-2,-3,-6
             0.1,0.2,0.3,0.6
         –

    ●   リダイレクトでファイルに保存
         –   $ ./hoge.sh | awk '{print $1,$2,$3,$4}' | tr ' ' ',' > hoge.csv




2011年7月2日                      第二回 LINUX女子部勉強会                             27
●   pukiwikiのテーブル
    ●   $ ./hoge.sh |
        awk '{for(i=1;i<=NF;i++){$i = "|" $i};print $0,"|"}'
           |1 |2 |3 |6 |
           |0.1 |0.2 |0.3 |0.6 |
           |-1 |-2 |-3 |-6 |
           |0.1 |0.2 |0.3 |0.6 |
●   reSTのcsvテーブル
    ●   $ ./hoge.sh | awk 'BEGIN{OFS=","}{for(i=1;i<=NF;i++){$i="""$i
        """};print}' | awk 'BEGIN{print ".. :csv-table:: たいとる";print ""}
        {print "t" $0}'
           .. :csv-table:: たいとる
              
              "1","2","3","6"
              "0.1","0.2","0.3","0.6"
              "-1","-2","-3","-6"
              "0.1","0.2","0.3","0.6"
2011年7月2日                          第二回 LINUX女子部勉強会                     28
●   HTML
    ●   $ ./hoge.sh | awk '{for(i=1;i<=NF;i++){$i = "<td>" $i
        "</td>"};print}' | awk '{print "<tr>" $0 "</tr>"}' | awk
        'BEGIN{print "<table>"}{print}END{print "</table>"}'
            <table>
            <tr><td>1</td> <td>2</td> <td>3</td> <td>6</td></tr>
            <tr><td>0.1</td> <td>0.2</td> <td>0.3</td>
            <td>0.6</td></tr>
            <tr><td>-1</td> <td>-2</td> <td>-3</td> <td>-6</td></tr>
            <tr><td>0.1</td> <td>0.2</td> <td>0.3</td>
            <td>0.6</td></tr>
            </table>
2011年7月2日                    第二回 LINUX女子部勉強会                           29
#!/bin/bash
                                        #html.sh
                                        cat << FIN
●   HTML その2                            <!DOCTYPE HTML PUBLIC "-//W3C//DTD
                                        HTML 4.01 Transitional//EN">
                                        <html>
     ●   真面目にHTMLを書く                          <head>
                                                   <meta http-equiv="content-type"
     ●   リダイレクトしてブラウザで                  content="text/html; charset=utf-8" />
                                              </head>
         閲覧                                   <body>
         –   $ ./html.sh >                         <table>
                                        FIN
             ~/public_html/table.html   cat ./hoge           |
                                        ./hoge.sh            |
                                        awk '{for(i=1;i<=NF;i++){$i = "<td>" $i
                                        "</td>"};print "<tr>" $0 "</tr>"}'
                                        cat << FIN
                                                   </table>
                                              </body>
                                        </html>
                                        FIN
    2011年7月2日                  第二回 LINUX女子部勉強会                                       30
●   なにか絵に書く(xy座標へ変換)
    ●   $ ./hoge.sh |
        awk '{for(i=1;i<=NF;i++){print "x=" NR, "y=" i, $i}}'
            x=1 y=1 1
            x=1 y=2 2
            x=1 y=3 3
            x=1 y=4 6
            x=2 y=1 0.1
            x=2 y=2 0.2
            x=2 y=3 0.3
            x=2 y=4 0.6
            x=3 y=1 -1
            x=3 y=2 …
2011年7月2日                 第二回 LINUX女子部勉強会                       31
お題C:CGIを書く
●   各ユーザのHDD使用量を表示
    ●   du -s dir : dir以下のファイル容量を集計
                                 #!/bin/bash
    ●   HTTPヘッダを出力した後、
        HTMLを出力                  echo 'Content-type: text/html'
                                 echo ""
                                 echo '<table border="1" cellspacing="0">'

                                 du -s /home/[a-z]* 2> /dev/null      |
    ●   POSTされたデータも              awk '{gsub(//home//,"",$2);print}' |
        読めます                     sort -k1,1nr                   |
                                 awk '{print int($1/1024) "MB", $2}' |
        –   ddコマンドなど             awk '{print "<tr><td>" $1 "</td><td>" $2
                                 "</td></tr>" }'
                                 echo "</table>"

                                 exit 0
2011年7月2日              第二回 LINUX女子部勉強会                                  32
お題D:ログを集計してみましょう
●   いろいろやばい、secureログ
     $ head -n 5 secure
     Jun 26 07:50:03 hoge01 sshd[12942]: Did not receive identification
     string from 122.176.82.13
     Jun 26 07:51:56 hoge01 sshd[12945]: reverse mapping checking
     getaddrinfo for abts-north-static-013.82.176.122.airtelbroadband.in
     failed - POSSIBLE BREAK-IN ATTEMPT!
     Jun 26 07:51:56 hoge01 sshd[12945]: pam_unix(sshd:auth):
     authentication failure; logname= uid=0 euid=0 tty=ssh ruser=
     rhost=122.176.82.13 user=root
     Jun 26 07:51:58 hoge01 sshd[12945]: Failed password for root
     from 122.176.82.13 port 55020 ssh2
     Jun 26 07:51:58 hoge01 sshd[12946]: Connection closed by
     122.176.82.13

2011年7月2日                  第二回 LINUX女子部勉強会                             33
まずやること
●   日付正規化                       #!/bin/bash
                                #ymd.sh
    スクリプトを作る                    #パイプから字を受ける
                                cat < /dev/stdin                           |
     ●   修正前                    awk '{gsub(/Jan/,"01",$1);print}'          |
                                awk '{gsub(/Feb/,"02",$1);print}'          |
         –   Jun 1 10:12:30     awk '{gsub(/Mar/,"03",$1);print}'
                                awk '{gsub(/Apl/,"04",$1);print}'
                                                                           |
                                                                           |
     ●   修正後                    awk '{gsub(/May/,"05",$1);print}'
                                awk '{gsub(/Jun/,"06",$1);print}'
                                                                           |
                                                                           |
                                awk '{gsub(/Jul/,"07",$1);print}'          |
         –   20110101 101230    awk '{gsub(/Aug/,"08",$1);print}'          |
             (ログに年が入って          awk '{gsub(/Sep/,"09",$1);print}'          |
                                awk '{gsub(/Oct/,"10",$1);print}'          |
             いないのは問題!)          awk '{gsub(/Nov/,"11",$1);print}'          |
                                awk '{gsub(/Dec/,"12",$1);print}'          |
                                awk '{gsub(/:/,"",$3);print}'              |
                                awk '{$2=sprintf("%02s",$2);print}'        |
     ●   ymd.sh                 awk '{print "2011" $0}'                    |
                                awk '{$1=$1 $2;$2="";print}'
         –   誰ですか
             笑っているのは?
    2011年7月2日                  第二回 LINUX女子部勉強会                        34
お題D-1:一日の不正アクセス件数集計
●   Failed passwordのレコードを数える
    ●   方法1
        –   $ cat secure* | ./ymd.sh | awk '$5=="Failed" &&
            $6=="password"{print $1}' | sort | awk 'BEGIN{a=0;d=0}
            {if(d!=$1){print d,a;d=$1;a=1}else{a++}}END{print d,a}' |
            tail -n +2
    ●   方法2(ユニケージコマンドを使う)
        –   $ cat secure* | ./ymd.sh | awk '$5=="Failed" &&
            $6=="password"{print $1}' | sort | count 1 1



2011年7月2日                   第二回 LINUX女子部勉強会                             35
●   アタックの多かった日のランキング
    ●   $ cat secure* | ./ymd.sh | awk '$5=="Failed" &&
        $6=="password"{print $1}' | sort | awk 'BEGIN{a=0;d=0}
        {if(d!=$1){print d,a;d=$1;a=1}else{a++}}END{print d,a}' | tail
        -n +2 | sort -k2,2nr | head -n 3
            20110602 12525
            20110613 9354
            20110614 3929
●   6月2日を見てみましょう
    ●   $ cat secure* | ./ymd.sh | awk '$1==20110602' > hoge


2011年7月2日                    第二回 LINUX女子部勉強会                        36
お題D-2:不正アクセス検知
●   以下の場合、パスワードが破られた可能性
    ●   あるIPからのログインがやたら失敗するが、
        一回以上成功している。




2011年7月2日       第二回 LINUX女子部勉強会   37
#!/bin/bash

./ymd.sh < /dev/stdin                                                                 |
awk '$6=="password"'                                                                  |
awk '$5=="Failed" || $5=="Accepted"'                                                  |
awk '{for(i=1;i<=NF;i++){if($i~/[0-9][0-9]*.[0-9]*.[0-9]*.[0-9]*/){print $i,$5}}}'  |
#$1: IP $2: Failed or Accepted
sort -k1,2                                                                            |
awk 'BEGIN{str=0;c=0}{if(str!=$0){print str,c;str=$0;c=1}else{c++}}'                    |
#$1: IP $2: Failed or Accepted $3:回数
tail -n +2                                                                              |
awk 'BEGIN{str=0}{if(str==$1){printf(" %s %sn",$2,$3)}else{printf("n%s",$0);str=$1}}' |
#AcceptedとFailureが両方存在するレコードを抽出
awk 'NF>3{print $1,$3,$5}'                                                              |
#$1:IP $2:成功の数 $3:失敗の数
#失敗の方が回数が多いレコードを抽出
awk '$2<$3'

2011年7月2日                         第二回 LINUX女子部勉強会                                           38
●   ユニケージ版
     #!/bin/bash

     ./ymd.sh < /dev/stdin                |
     awk '$6=="password"'                   |
     awk '$5=="Failed" || $5=="Accepted"' |
     awk '{for(i=1;i<=NF;i++){if($i~/[0-9][0-9]*.[0-9]*.[0-9]*.[0-9]*/){print $i,$5}}}' |
     #$1: IP $2: Failed or Accepted
     sort -k1,2                    |
     count 1 2                       |
     #$1: IP $2: Failed or Accepted $3:回数
     yarr num=1                        |
     awk 'NF==5'                        |
     self 1 3 5                    |
     #$1:IP $2:成功の数 $3:失敗の数
     #失敗の方が回数が多いレコードを抽出
     awk '$2<$3'

2011年7月2日                           第二回 LINUX女子部勉強会                                            39
お題E:データの連結(join操作)
                                                      Jan 01
                                                      Feb 02
●   次のファイルを連結                                         Mar 03
                                                      Apl 04
    ●   マスタ:                                          May 05
                                                      Jun 06
         月(英字)と月(数字)の対応表                              Jul 07
                                                      Aug 08
    ●   トランザクション:secureログ                             Sep 09
                                                      Oct 10
    ●   トランザクションにマスタをくっつけて、                           Nov 11
                                                      Dec 12
        Jan, Feb, Mar, ...を取り除く                    マスタファイル

                                     Jun 26 07:50:03 hoge01 ...
                                     Jun 26 07:51:56 hoge01 ...
                                     Jun 26 07:51:56 hoge01 ...
                                     Jun 26 07:51:58 hoge01 ...
                                     Jun 26 07:51:58 hoge01 ...

                                        トランザクションファイル
2011年7月2日          第二回 LINUX女子部勉強会                                40
●   ちなみにユニケージだとこれだけ
     #!/bin/bash

     tmp=/tmp/$$

     sort -k1,1 ./MONTHS    > $tmp-master

     cat ../secure*                 |
     cjoin1 key=1 $tmp-master -     |
     delf 1

     rm $tmp-master
     exit 0

      06 26 07:51:56 hoge01 sshd[12945]: pam_unix(sshd:auth): ...
      06 26 07:51:58 hoge01 sshd[12945]: Failed password ...
      06 26 07:51:58 hoge01 sshd[12946]: Connection closed by 122.176.82.13
      ...
2011年7月2日                         第二回 LINUX女子部勉強会                             41
●   awkとsortでもなんとかなる
            #!/bin/bash

            tmp=/tmp/$$

            sort -k1,1 ./MONTHS           |
            awk '{print $1,"00",$2}'      > $tmp-months

            cat ../secure*          |
            sort -k1,1              |
            sort -m $tmp-months - |
            awk '{if($2=="00"){v=$3}else{$1=v;print}}'

            rm -f $tmp-*
            exit 0


2011年7月2日                  第二回 LINUX女子部勉強会                42
3.まとめ
●   awkでテキストデータと戯れる
    ●   このスライドのawkの数:62個
    ●   地味。腹筋なみに地味
    ●   パズルと思えばおもしろい

    ●   重要:OSや基盤技術に非常に近い場所での作業
        –   標準入出力、ログ、HTTP、HTML、・・・
        –   マウスを多用するようなツールをたくさん覚えるよりは有意義


●   これも重要:一緒に勉強したい方、USP友の会まで
2011年7月2日              第二回 LINUX女子部勉強会     43
4. 発表後記
●   全部awkで何とかしろということではありません
    ●   コマンドを覚えて、より短いスクリプトを書きましょう
        –   短さはシェルスクリプトの最大の利点
    ●   やりたい処理ができなかったら、その場はawkで
        なんとかして後からコマンドを調べる

●   言い忘れたこと
    ●   USP出版で「プログラミング言語awk」扱ってます
        –   http://www.usp-lab.com/pub/book.awk.html

2011年7月2日                  第二回 LINUX女子部勉強会             44

Linux女子部第二回勉強会usp友の会

  • 1.
    ビル・ゲイツも知ってる!? シェルスクリプトでLinuxを 256倍使いこなそう!! USP友の会 上田隆一 2011年7月2日 第二回 LINUX女子部勉強会
  • 2.
    contents ● -1. USP友の会の紹介 ● 0. 自己紹介 ● 1. Linux使いの嗜み、シェルスクリプト ● 2. awkをシェルスクリプトで使い倒す ● (一部、ユニケージの話) ● 3. まとめ 2011年7月2日 第二回 LINUX女子部勉強会 2
  • 3.
    -1. USP友の会 ● シェルスクリプト(CUI)のコミュニティー ● USP: universal shell programming ● 会員数:もうすぐ200人(200人目に粗品贈呈) ● 会の綱領 ● 「酒は呑め呑め呑むならば(嘘)」 ● 「本物の技術・本物の人」 派手なウェブサイト 2011年7月2日 第二回 LINUX女子部勉強会 雑誌:USPマガジン 3
  • 4.
    遊びにきてね ● イベント ● 8月2日(火):定例会@東京湾納涼船 ● 8月13日(土):某イベントでUSPマガジンを売る – 東京ビッグサイト 東2ホール S-53b ● 8月末:勉強会 ● 9月22日(木):Tech LION vol. 3 ● ネット・メディア ● Twitter @usptomo(残念な駄洒落のみ) ● Facebook 「USP友の会」(イベント等の告知) 2011年7月2日 第二回 LINUX女子部勉強会 4
  • 5.
    0. 自己紹介 ● 上田隆一 ● 1978年生まれ33歳 ● 博士(工学) – 学位論文:State-Action Map Compression by using Vector Quantization for Decision Making of Autonomous Robots ● 26歳~30歳:東大で常勤の助手→助教 – 新人賞のようなものをぽちぽち受賞 – 教科書の翻訳(確率ロボティクス) ● 31歳:やりたいことに能力がついていかず、大学を辞める – USP研究所のやっていることが面白くて入社 2011年7月2日 第二回 LINUX女子部勉強会 5
  • 6.
    興味・野望 ● シェルスクリプト, CUI一行野郎 ● もともとwindowsで研究のプログラムを書いていたので新鮮 ● (仮称)次世代アナログコンピュータの構想 ● ポテンシャル場やベクトル場等をO(1)で計算する何か – 非言語型の人工知能が実現 → 世の中ひっくり返る ● はやく10億円貯めて、物理と化学を勉強して研究にとりかかりたい – 貯金に1000年、研究に30年 ● カミさんの機嫌をとる手法の研究 ● 娘を真人間にする方法 2011年7月2日 第二回 LINUX女子部勉強会 6
  • 7.
    1. Linux使いの嗜み、シェルスクリプト ● UNIXの生い立ち ● テキストはユニバーサルなフォーマット 2011年7月2日 第二回 LINUX女子部勉強会 7
  • 8.
    UNIXの生い立ち ● 誕生:1969年 ● UNIXが乗った最初の計算機 ● DEC PDP-7(1965年発売) PDP-7 (wikipediaより引用) ● メモリ:9kB~144kB – http://www.linfo.org/pdp-7.html 2011年7月2日 第二回 LINUX女子部勉強会 8
  • 9.
    UNIXのテキスト文化 ● UNIX(Linux)は、文字で設定を行う ● 例: ● 文字はメモリを食う ● on/offの設定:ゼロイチだと1bit、「on」「off」だと最大24bitで24倍 – バイナリ: 1 – 文字(ASCIIコード): 11011110110011001100110 ● PDP-7では深刻な問題になりうる ● なぜ、文字を選んだ??? 2011年7月2日 第二回 LINUX女子部勉強会 9
  • 10.
    テキストは便利 ● CUIしか無かった:人間が設定を書きやすい。 ● 今はGUIがあるが、それでも文字の設定ファイルを利用 ● ↑単なるレガシーなのか?? ● コマンド+パイプ ● 何でもcat, grep, moreで確認 ● バイナリファイル:専用のエディタが必要 – バグ・無理な拡張の巣窟、プログラムが肥大 2011年7月2日 第二回 LINUX女子部勉強会 10
  • 11.
    バイナリは(儲かるかもしれないが本質的には)面倒 ● 例えば、専用バイナリ形式のワープロソフトを考える ● そのワープロ専用の機能がたくさん – 文字列検索・置換機能、文字数カウント機能、スペルチェッカー、 画像埋め込み機能・・・ ● アプリケーション1個に対して機能がO(n)個 ● TeXを考える ● テキストファイルをdviにできればそれでよい。 ● アプリケーション1個に対して機能はO(1)個 2011年7月2日 第二回 LINUX女子部勉強会 11
  • 12.
    偉い人も、言っている ● UNIX哲学 [Gancarz2001] ● 小さいものは美しい。 ● 各プログラムが一つのことをうまくやるようにせよ。 ● できる限り原型(プロトタイプ)を作れ。 ● 効率よりも移植しやすさを選べ。 ● 単純なテキストファイルにデータを格納せよ。 ● ソフトウェアの効率をきみの優位さとして利用せよ。 ● 効率と移植性を高めるためにシェルスクリプトを利用せよ。 ● 束縛するインターフェースは作るな。 ● 全てのプログラムはフィルタとして振る舞うようにせよ。 2011年7月2日 第二回 LINUX女子部勉強会 12
  • 13.
    時代はテキスト ● 事例1:バイナリ形式のテキスト化 ● Office 2007 – データ形式:zipで圧縮されたxml ● 理由 – バイナリフォーマットはソフト屋に抱え込まれるという世論 – 計算機が強力になった – バイナリ形式がややこしすぎて管理できなくなった? ● 事例2:サービスのweb化 ● HTTPは文字でデータをやりとり 2011年7月2日 第二回 LINUX女子部勉強会 13
  • 14.
    これからのものはテキスト主流 ● 最近の注目:Sphinx ● ドキュメント作成ツール – ReST(reStructuredText)形式というテキストで作文 – webページ、pdf、ePub等様々な形式に変換してくれる – 機能拡張に大きな可能性 ● 今後の(勝手な)予想 ● ppmやpgmをgzip圧縮した画像が主流に? ● ムービーファイルのテキスト化!(時刻、座標、rgbの羅列) ・・・だってわかりやすい方がいいじゃないですか。 2011年7月2日 第二回 LINUX女子部勉強会 14
  • 15.
    ・・・ということで ● Linuxをいじるならば、コマンドを使った テキスト処理に強くなろう! ● UNIX系OS使いのタシナミ ● UNIX系OS使いの基礎体力 – もしかしたら今日の内容は直接役に立たないかもしれませんが、 端末をいじるあらゆる局面でじわじわ効いてきます。 2011年7月2日 第二回 LINUX女子部勉強会 15
  • 16.
    2. awkをシェルスクリプトで使い倒す ● ログなどの処理に便利なコマンド ● awkをパイプでつなげてシェルスクリプトを書くと、 かなりの種類の処理が可能になる。 2011年7月2日 第二回 LINUX女子部勉強会 16
  • 17.
    awk ● 古いスクリプト言語 ● 開発陣 ● Alfred Aho(ベル研→コロンビア大教授) – 著書:コンパイラ—原理・技法・ツール ● Peter Weinberger(ベル研→google) ● Brian Kernighan(ベル研→プリンストン大教授) – 著書:プログラミング言語C ● 言語なんですが、コマンドのように使います。 2011年7月2日 第二回 LINUX女子部勉強会 17
  • 18.
    とりあえず使ってみる ● こんなファイル(hogeという名前) a 100 b 20 c -10.4 ● コマンドを打つ ● cat hoge | awk '{print $1}' ● cat hoge | awk '$1=="b"' ● cat hoge | awk 'BEGIN{a=0}{a+=$2}END{print a}' 2011年7月2日 第二回 LINUX女子部勉強会 18
  • 19.
    awkの挙動 ● いかにもUNIX的(フィールド指向) ● 空白で区切った表を標準入力で読み取る ● 文字列を割って$1, $2, $3, ...という変数に入れる ● 「データはこの様に持て」というメッセージ? ● 後はユーザの組んだ一行プログラムでいかようにも ● 検索、計算、文字列処理・・・ 2011年7月2日 第二回 LINUX女子部勉強会 19
  • 20.
    お題A:表計算をやってみましょう ● 注意:コードを追わず、何ができるかだけ、ぼんやり 覚えてください。コードを追うと撃沈します。 ● ファイル(hoge) 1 2 3 0.1 0.2 0.3 -1 -2 -3 ● 横に足す ● $ cat hoge | awk '{print $1,$2,$3,$1+$2+$3}' 1236 0.1 0.2 0.3 0.6 -1 -2 -3 -6 2011年7月2日 第二回 LINUX女子部勉強会 20
  • 21.
    $0に、一行すべての文字列が入っている ● $ cat hoge | awk '{print $0,$1+$2+$3}' 1 2 36 0.1 0.2 0.3 0.6 -1 -2 -3 -6 ● 変数も使えます ● $ cat hoge | awk '{sum=$1+$2+$3;print $0,sum}' 1 2 36 0.1 0.2 0.3 0.6 -1 -2 -3 -6 2011年7月2日 第二回 LINUX女子部勉強会 21
  • 22.
    書式を整える ● $ cat hoge | awk '{sum=$1+$2+$3;print $0, sprintf("%10s",sum)}' 1 2 3 6 0.1 0.2 0.3 0.6 -1 -2 -3 -6 ● 面倒なのでfor文で ● $ cat hoge | awk '{$4=$1+$2+$3;for(i=1;i<=4;i++) {printf("%5s",$i)};printf("n")}' 1 2 3 6 0.1 0.2 0.3 0.6 -1 -2 -3 -6 2011年7月2日 第二回 LINUX女子部勉強会 22
  • 23.
    ややこしくなったらパイプで処理を分ける ● $ cat hoge | awk '{print $0,$1+$2+$3}' | awk '{for(i=1;i<=4;i++){printf("%5s",$i)};printf("n")}' 1 2 3 6 0.1 0.2 0.3 0.6 -1 -2 -3 -6 2011年7月2日 第二回 LINUX女子部勉強会 23
  • 24.
    縦にも足してみましょう ● $ cat hoge | awk '{print $0,$1+$2+$3}' | awk '{for(i=1;i<=4;i++){a[i]+=$i};print}END{print a[1],a[2],a[3],a[4]}' | awk '{for(i=1;i<=NF;i++) {printf("%5s",$i)};printf("n")}' 1 2 3 6 0.1 0.2 0.3 0.6 -1 -2 -3 -6 0.1 0.2 0.3 0.6 ● さすがに読み返せない。どうするか? 2011年7月2日 第二回 LINUX女子部勉強会 24
  • 25.
    シェルスクリプトにする ● 基本、手で打つコマンドラインを ファイルに書いただけのもの ● 便利な点 ● 保存できる #!/bin/bash #hoge.sh ● コメントを書ける cat hoge       | #$1~$3: 数値 #各レコードの値を足して後ろにくっつける awk '{print $0,$1+$2+$3}'    | 処理を細かく区切って #$1~$3:数値 $4:合計値 データのレイアウトだけ #各フィールドの数値を足して最終行に出力 書いておけば、コードが awk '{for(i=1;i<=4;i++){a[i]+=$i};print} 読みにくくても困らない。 END{print a[1],a[2],a[3],a[4]}' 2011年7月2日 第二回 LINUX女子部勉強会 25
  • 26.
    お題B:出力にこだわる ● ところで、出力がCUI上というのは寂しい。 ● いや、寂しくないが、需要が多い。 ● テキストの出力は貧弱? ● テキストだから何にでも化けるだろう。 2011年7月2日 第二回 LINUX女子部勉強会 26
  • 27.
    csv ● $ ./hoge.sh | awk '{print $1,$2,$3,$4}' | tr ' ' ',' 1,2,3,6 0.1,0.2,0.3,0.6 -1,-2,-3,-6 0.1,0.2,0.3,0.6 – ● リダイレクトでファイルに保存 – $ ./hoge.sh | awk '{print $1,$2,$3,$4}' | tr ' ' ',' > hoge.csv 2011年7月2日 第二回 LINUX女子部勉強会 27
  • 28.
    pukiwikiのテーブル ● $ ./hoge.sh | awk '{for(i=1;i<=NF;i++){$i = "|" $i};print $0,"|"}' |1 |2 |3 |6 | |0.1 |0.2 |0.3 |0.6 | |-1 |-2 |-3 |-6 | |0.1 |0.2 |0.3 |0.6 | ● reSTのcsvテーブル ● $ ./hoge.sh | awk 'BEGIN{OFS=","}{for(i=1;i<=NF;i++){$i="""$i """};print}' | awk 'BEGIN{print ".. :csv-table:: たいとる";print ""} {print "t" $0}' .. :csv-table:: たいとる        "1","2","3","6"    "0.1","0.2","0.3","0.6"    "-1","-2","-3","-6"    "0.1","0.2","0.3","0.6" 2011年7月2日 第二回 LINUX女子部勉強会 28
  • 29.
    HTML ● $ ./hoge.sh | awk '{for(i=1;i<=NF;i++){$i = "<td>" $i "</td>"};print}' | awk '{print "<tr>" $0 "</tr>"}' | awk 'BEGIN{print "<table>"}{print}END{print "</table>"}' <table> <tr><td>1</td> <td>2</td> <td>3</td> <td>6</td></tr> <tr><td>0.1</td> <td>0.2</td> <td>0.3</td> <td>0.6</td></tr> <tr><td>-1</td> <td>-2</td> <td>-3</td> <td>-6</td></tr> <tr><td>0.1</td> <td>0.2</td> <td>0.3</td> <td>0.6</td></tr> </table> 2011年7月2日 第二回 LINUX女子部勉強会 29
  • 30.
    #!/bin/bash #html.sh cat << FIN ● HTML その2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> ● 真面目にHTMLを書く <head> <meta http-equiv="content-type" ● リダイレクトしてブラウザで content="text/html; charset=utf-8" /> </head> 閲覧 <body> – $ ./html.sh > <table> FIN ~/public_html/table.html cat ./hoge | ./hoge.sh | awk '{for(i=1;i<=NF;i++){$i = "<td>" $i "</td>"};print "<tr>" $0 "</tr>"}' cat << FIN </table> </body> </html> FIN 2011年7月2日 第二回 LINUX女子部勉強会 30
  • 31.
    なにか絵に書く(xy座標へ変換) ● $ ./hoge.sh | awk '{for(i=1;i<=NF;i++){print "x=" NR, "y=" i, $i}}' x=1 y=1 1 x=1 y=2 2 x=1 y=3 3 x=1 y=4 6 x=2 y=1 0.1 x=2 y=2 0.2 x=2 y=3 0.3 x=2 y=4 0.6 x=3 y=1 -1 x=3 y=2 … 2011年7月2日 第二回 LINUX女子部勉強会 31
  • 32.
    お題C:CGIを書く ● 各ユーザのHDD使用量を表示 ● du -s dir : dir以下のファイル容量を集計 #!/bin/bash ● HTTPヘッダを出力した後、 HTMLを出力 echo 'Content-type: text/html' echo "" echo '<table border="1" cellspacing="0">' du -s /home/[a-z]* 2> /dev/null | ● POSTされたデータも awk '{gsub(//home//,"",$2);print}' | 読めます sort -k1,1nr | awk '{print int($1/1024) "MB", $2}' | – ddコマンドなど awk '{print "<tr><td>" $1 "</td><td>" $2 "</td></tr>" }' echo "</table>" exit 0 2011年7月2日 第二回 LINUX女子部勉強会 32
  • 33.
    お題D:ログを集計してみましょう ● いろいろやばい、secureログ $ head -n 5 secure Jun 26 07:50:03 hoge01 sshd[12942]: Did not receive identification string from 122.176.82.13 Jun 26 07:51:56 hoge01 sshd[12945]: reverse mapping checking getaddrinfo for abts-north-static-013.82.176.122.airtelbroadband.in failed - POSSIBLE BREAK-IN ATTEMPT! Jun 26 07:51:56 hoge01 sshd[12945]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=122.176.82.13 user=root Jun 26 07:51:58 hoge01 sshd[12945]: Failed password for root from 122.176.82.13 port 55020 ssh2 Jun 26 07:51:58 hoge01 sshd[12946]: Connection closed by 122.176.82.13 2011年7月2日 第二回 LINUX女子部勉強会 33
  • 34.
    まずやること ● 日付正規化 #!/bin/bash #ymd.sh スクリプトを作る #パイプから字を受ける cat < /dev/stdin | ● 修正前 awk '{gsub(/Jan/,"01",$1);print}' | awk '{gsub(/Feb/,"02",$1);print}' | – Jun 1 10:12:30 awk '{gsub(/Mar/,"03",$1);print}' awk '{gsub(/Apl/,"04",$1);print}' | | ● 修正後 awk '{gsub(/May/,"05",$1);print}' awk '{gsub(/Jun/,"06",$1);print}' | | awk '{gsub(/Jul/,"07",$1);print}' | – 20110101 101230 awk '{gsub(/Aug/,"08",$1);print}' | (ログに年が入って awk '{gsub(/Sep/,"09",$1);print}' | awk '{gsub(/Oct/,"10",$1);print}' | いないのは問題!) awk '{gsub(/Nov/,"11",$1);print}' | awk '{gsub(/Dec/,"12",$1);print}' | awk '{gsub(/:/,"",$3);print}' | awk '{$2=sprintf("%02s",$2);print}' | ● ymd.sh awk '{print "2011" $0}' | awk '{$1=$1 $2;$2="";print}' – 誰ですか 笑っているのは? 2011年7月2日 第二回 LINUX女子部勉強会 34
  • 35.
    お題D-1:一日の不正アクセス件数集計 ● Failed passwordのレコードを数える ● 方法1 – $ cat secure* | ./ymd.sh | awk '$5=="Failed" && $6=="password"{print $1}' | sort | awk 'BEGIN{a=0;d=0} {if(d!=$1){print d,a;d=$1;a=1}else{a++}}END{print d,a}' | tail -n +2 ● 方法2(ユニケージコマンドを使う) – $ cat secure* | ./ymd.sh | awk '$5=="Failed" && $6=="password"{print $1}' | sort | count 1 1 2011年7月2日 第二回 LINUX女子部勉強会 35
  • 36.
    アタックの多かった日のランキング ● $ cat secure* | ./ymd.sh | awk '$5=="Failed" && $6=="password"{print $1}' | sort | awk 'BEGIN{a=0;d=0} {if(d!=$1){print d,a;d=$1;a=1}else{a++}}END{print d,a}' | tail -n +2 | sort -k2,2nr | head -n 3 20110602 12525 20110613 9354 20110614 3929 ● 6月2日を見てみましょう ● $ cat secure* | ./ymd.sh | awk '$1==20110602' > hoge 2011年7月2日 第二回 LINUX女子部勉強会 36
  • 37.
    お題D-2:不正アクセス検知 ● 以下の場合、パスワードが破られた可能性 ● あるIPからのログインがやたら失敗するが、 一回以上成功している。 2011年7月2日 第二回 LINUX女子部勉強会 37
  • 38.
    #!/bin/bash ./ymd.sh < /dev/stdin | awk '$6=="password"' | awk '$5=="Failed" || $5=="Accepted"' | awk '{for(i=1;i<=NF;i++){if($i~/[0-9][0-9]*.[0-9]*.[0-9]*.[0-9]*/){print $i,$5}}}' | #$1: IP $2: Failed or Accepted sort -k1,2 | awk 'BEGIN{str=0;c=0}{if(str!=$0){print str,c;str=$0;c=1}else{c++}}' | #$1: IP $2: Failed or Accepted $3:回数 tail -n +2 | awk 'BEGIN{str=0}{if(str==$1){printf(" %s %sn",$2,$3)}else{printf("n%s",$0);str=$1}}' | #AcceptedとFailureが両方存在するレコードを抽出 awk 'NF>3{print $1,$3,$5}' | #$1:IP $2:成功の数 $3:失敗の数 #失敗の方が回数が多いレコードを抽出 awk '$2<$3' 2011年7月2日 第二回 LINUX女子部勉強会 38
  • 39.
    ユニケージ版 #!/bin/bash ./ymd.sh < /dev/stdin | awk '$6=="password"' | awk '$5=="Failed" || $5=="Accepted"' | awk '{for(i=1;i<=NF;i++){if($i~/[0-9][0-9]*.[0-9]*.[0-9]*.[0-9]*/){print $i,$5}}}' | #$1: IP $2: Failed or Accepted sort -k1,2 | count 1 2 | #$1: IP $2: Failed or Accepted $3:回数 yarr num=1 | awk 'NF==5' | self 1 3 5 | #$1:IP $2:成功の数 $3:失敗の数 #失敗の方が回数が多いレコードを抽出 awk '$2<$3' 2011年7月2日 第二回 LINUX女子部勉強会 39
  • 40.
    お題E:データの連結(join操作) Jan 01 Feb 02 ● 次のファイルを連結 Mar 03 Apl 04 ● マスタ: May 05 Jun 06 月(英字)と月(数字)の対応表 Jul 07 Aug 08 ● トランザクション:secureログ Sep 09 Oct 10 ● トランザクションにマスタをくっつけて、 Nov 11 Dec 12 Jan, Feb, Mar, ...を取り除く マスタファイル Jun 26 07:50:03 hoge01 ... Jun 26 07:51:56 hoge01 ... Jun 26 07:51:56 hoge01 ... Jun 26 07:51:58 hoge01 ... Jun 26 07:51:58 hoge01 ... トランザクションファイル 2011年7月2日 第二回 LINUX女子部勉強会 40
  • 41.
    ちなみにユニケージだとこれだけ #!/bin/bash tmp=/tmp/$$ sort -k1,1 ./MONTHS > $tmp-master cat ../secure* | cjoin1 key=1 $tmp-master - | delf 1 rm $tmp-master exit 0 06 26 07:51:56 hoge01 sshd[12945]: pam_unix(sshd:auth): ... 06 26 07:51:58 hoge01 sshd[12945]: Failed password ... 06 26 07:51:58 hoge01 sshd[12946]: Connection closed by 122.176.82.13 ... 2011年7月2日 第二回 LINUX女子部勉強会 41
  • 42.
    awkとsortでもなんとかなる #!/bin/bash tmp=/tmp/$$ sort -k1,1 ./MONTHS | awk '{print $1,"00",$2}' > $tmp-months cat ../secure* | sort -k1,1 | sort -m $tmp-months - | awk '{if($2=="00"){v=$3}else{$1=v;print}}' rm -f $tmp-* exit 0 2011年7月2日 第二回 LINUX女子部勉強会 42
  • 43.
    3.まとめ ● awkでテキストデータと戯れる ● このスライドのawkの数:62個 ● 地味。腹筋なみに地味 ● パズルと思えばおもしろい ● 重要:OSや基盤技術に非常に近い場所での作業 – 標準入出力、ログ、HTTP、HTML、・・・ – マウスを多用するようなツールをたくさん覚えるよりは有意義 ● これも重要:一緒に勉強したい方、USP友の会まで 2011年7月2日 第二回 LINUX女子部勉強会 43
  • 44.
    4. 発表後記 ● 全部awkで何とかしろということではありません ● コマンドを覚えて、より短いスクリプトを書きましょう – 短さはシェルスクリプトの最大の利点 ● やりたい処理ができなかったら、その場はawkで なんとかして後からコマンドを調べる ● 言い忘れたこと ● USP出版で「プログラミング言語awk」扱ってます – http://www.usp-lab.com/pub/book.awk.html 2011年7月2日 第二回 LINUX女子部勉強会 44