awkの主要オプションと配列の利用方法、および本番環境データの統計処理

awkの主なオプションのまとめ

外部環境変数をawkで使用する(-vオプション)

awk -v num2="$num1" -v var1="$var" 'BEGIN{print num2,var1}'

-fオプションによるスクリプトファイルからの読み込み

  1. awkスクリプトファイル(1.awk):
BEGIN{
    str="I hava a tream"
    location=index(str,"ea")
    print location
}
awk -f 1.awk
  1. カスタムawkファイル(wak):
BEGIN{
    str="Transaction 243 Start,Event ID:9002"
    count=sub(/[0-9]+/,"$",str)
    print str
}

-Fオプションによるフィールド区切り文字の指定

awk -F ":" '{print $7}' passwd 

バージョン情報の表示

awk -V

awkにおける配列の活用と本番データの分析例

シェルにおける配列操作:

  • シェルの配列インデックスは0から始まる
    array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
    要素の出力:        echo ${array[2]}
    要素数の取得:       echo ${#array[@]}
    特定要素の長さ:     echo ${#array[3]}
        
    要素への代入:       array[3]=ui;
    要素の削除:         unset array[2];unset array # 配列全体の削除
    部分アクセス:       echo ${array[@]:1:3}
    要素置換:           ${array[@]/e/E} 最初のeのみ置換; ${array[@]//e/E} 全てのeを置換

配列の走査:

for a in ${array[@]}
do
    echo $a
done

awkにおける配列の使用:

  • awkでは、配列の添字として数字だけでなく文字列も使用可能

代表的な使用例:

TCP接続状態ごとにカウントする

netstat -an | grep tcp | awk '{arr[$6]++}END{for (i in arr) print i,arr[i]}'

横方向合計と縦方向合計の計算

statics.awk

        BEGIN{
            printf "%-30s%-30s%-30s%-30s%-30s%-30s\n","Name","Yuwen","Math","English","Physical","total"
        }
        {
            total=$2+$3+$4+$5
            yuwen_sum+=$2
            math_sum+=$3
            english_sum+=$4
            physical_sum+=$5
            printf "%-30s%-30d%-30d%-30d%-30d%-30d\n",$1,$2,$3,$4,$5,total
        }
        END{
            printf "%-30s%-30d%-30d%-30d%-30d\n","every_total",yuwen_sum,math_sum,english_sum,physical_sum
        }
awk -f statics.awk student.txt 

文字列長の取得:

str="test string"
echo ${#str}

配列要素の更新:

array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
array[1]="Jerry"
echo ${array[@]}

3番目の要素を削除:

echo ${array[@]}
unset array[2]
echo ${array[@]}

1番目の要素(Mike)を削除し、再度1番目を削除した場合、配列が変更されないことを確認。要素は削除されているが、インデックスは保持される

array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
unset array[1]
echo ${array[*]}

部分配列アクセス(インデックス1から3個)

array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
echo ${array[@]:1:3}

インデックス1から最後まで

echo ${array[@]:1}

1回置換、全置換

echo ${array[@]}
echo ${array[@]/e/E}
echo ${array[@]//e/E}

配列の反復処理

for a in ${array[@]};do echo $a;done

横方向と縦方向の合計値計算

awk -f stu.awk student.txt 

本番環境シミュレーションデータ処理スクリプト

db.log.20190608

2019-06-08 10:31:40 15459 Batches: user Jerry insert 5504 records into datebase:product table:detail, insert 5253 records successfully,failed 251 records
2019-06-08 10:31:40 15460 Batches: user Tracy insert 25114 records into datebase:product table:detail, insert 13340 records successfully,failed 11774 records
2019-06-08 10:31:40 15461 Batches: user Hanmeimei insert 13840 records into datebase:product table:detail, insert 5108 records successfully,failed 8732 records
2019-06-08 10:31:40 15462 Batches: user Lilei insert 32691 records into datebase:product table:detail, insert 5780 records successfully,failed 26911 records
2019-06-08 10:31:40 15463 Batches: user Allen insert 25902 records into datebase:product table:detail, insert 14027 records successfully,failed 11875 records

1 各ユーザーごとの挿入レコード数をカウント

exam1.awk

    BEGIN{
        printf "%-20s%-20s\n","User","Total records"
    }

    {
        USER[$6]+=$8
    }

    END{
        for(u in USER)
            printf "%-20s%-20d\n",u,USER[u]
    }
awk -f exam1.awk  db.log.20190608

2 各ユーザーの成功・失敗レコード数をカウント

exam2.awk

    BEGIN{
        printf "%-30s%-30s%-30s\n","User","Success records","Failed records"
    }

    {
        SUCCESS[$6]+=$14
        FAILED[$6]+=$17
    }

    END{
        for(u in SUCCESS)
            printf "%-30s%-30d%-30d\n",u,SUCCESS[u],FAILED[u]
    }
awk -f exam2.awk db.log.20190608 

3 上記1と2の結果を結合して、それぞれのユーザーの総挿入数・成功数・失敗数を表示

exam3.awk

    BEGIN{
        printf "%-30s%-30s%-30s%-30s\n","Name","total records","success records","failed records"
    }

    {
        TOTAL_RECORDS[$6]+=$8
        SUCCESS[$6]+=$14
        FAILED[$6]+=$17
    }

    END{
        for(u in TOTAL_RECORDS)
            printf "%-30s%-30d%-30d%-30d\n",u,TOTAL_RECORDS[u],SUCCESS[u],FAILED[u]
    }
awk -f exam3.awk db.log.20190608 

4 3の結果に加えて、合計を表示

exam4_b.awk

    BEGIN{
        printf "%-30s%-30s%-30s%-30s\n","Name","total records","success records","failed records"
    }

    {
        TOTAL_RECORDS[$6]+=$8
        SUCCESS[$6]+=$14
        FAILED[$6]+=$17
    }

    END{
        for(u in TOTAL_RECORDS)
        {
            # 結果配列から合計を計算
            records_sum+=TOTAL_RECORDS[u]
            success_sum+=SUCCESS[u]
            failed_sum+=FAILED[u]
            printf "%-30s%-30d%-30d%-30d\n",u,TOTAL_RECORDS[u],SUCCESS[u],FAILED[u]
        }

        printf "%-30s%-30d%-30d%-30d\n","",records_sum,success_sum,failed_sum
    }
awk -f exam4_b.awk db.log.20190608

方法2:

exam4.awk

    BEGIN{
        printf "%-30s%-30s%-30s%-30s\n","Name","total records","success records","failed records"
    }

    {
        RECORDS[$6]+=$8
        SUCCESS[$6]+=$14
        FAILED[$6]+=$17
        
        # データを直接集計
        records_sum+=$8
        success_sum+=$14
        failed_sum+=$17    
    }

    END{
        for(u in RECORDS)
            printf "%-30s%-30d%-30d%-30d\n",u,RECORDS[u],SUCCESS[u],FAILED[u]

        printf "%-30s%-30d%-30d%-30d\n","total",records_sum,success_sum,failed_sum
    }

5 データ整合性チェック:成功+失敗数 ≠ 挿入総数の場合を検索し、行番号とログを表示

awk '{if($8!=$14+$17) print NR,$0}' db.log.20190608

ファイルへの出力:

exam5.awk

    BEGIN{
    }
    {
        if($8!=$14+$17) 
        print NR,$0
    }
awk -f exam5.awk db.log.20190608

タグ: awk 配列 データ統計 ログ解析 Shell

6月15日 23:03 投稿