awk 留底

 
 
由於常常作awk編碼,並且跨過一段時間就容易忘記,故在此作個留底。便於翻閱。——後期會在這個頁面不斷補充!
 

經常使用常量
 
 
屬性 描述
NR  已讀入的總記錄數
 ARGIND  當前被處理參數標誌 
FILENAME  當前輸入文件名
FS   輸入域分隔符,默認爲一個空格
RS   輸入記錄分隔符
NF  當前記錄裏域個數
 SUBSEP 下標分隔符 "\034" 
 

獲取日期
 
strftime("%Y-%m-%d", systime())

加載awk文件方式
 
 awk -v "file_name=`basename $file`" -f cut_online.awk $file
 

處理多個文件的時候,區分文件
 
 
區分:
 
 

數組操做
 
 
  awk的數組,一種關聯數組(Associative Arrays),下標能夠是數字和字符串。因無需對數組名和元素提早聲明,也無需指定元素個數 ,因此awk的數組使用很是靈活。
首先介紹下幾個awk數組相關的知識點:
<1>創建數組
array[index] = value :數組名array,下標index以及相應的值value。

<2>讀取數組值html

{ for (item in array)  print array[item]} # 輸出的順序是隨機的
{for(i=1;i<=len;i++)  print array[i]} # Len 是數組的長度

<3>多維數組,array[index1,index2,……]:SUBSEP是數組下標分割符,默認爲「\034」。能夠事先設定SUBSEP,也能夠直接在SUBSEP的位置輸入你要用的分隔符,如:python

awk 'BEGIN{SUBSEP=":";array["a","b"]=1;for(i in array) print i}'
a:b
awk 'BEGIN{array["a"":""b"]=1;for(i in array) print i}'
a:b

但,有些特殊狀況須要避免,如:shell

awk 'BEGIN{
SUBSEP=":"
array["a","b:c"]=1               # 下標爲「a:b:c」
array["a:b","c"]=2               #下標一樣是「a:b:c」
for (i in array) print i,array[i]}'
a:b:c 2                                 #因此數組元素只有一個。

<4>刪除數組或數組元素: 使用delete 函數數組

delete array                     #刪除整個數組
delete array[item]           # 刪除某個數組元素(item)

<5> 排序:awk中的asort函數能夠實現對數組的值進行排序,不過排序以後的數組下標改成從1到數組的長度。在gawk 3.1.2之後的版本還提供了一個asorti函數,這個函數不是依據關聯數組的值,而是依據關聯數組的下標排序,即asorti(array)之後,仍會用數字(1到數組長度)來做爲下標,可是array的數組值變爲排序後的原來的下標,除非你指定另外一個參數如:asorti(a,b)。 bash

echo 'aa
bb
aa
bb
cc' |\
awk '{a[$0]++}END{l=asorti(a);for(i=1;i<=l;i++)print a[i]}'
aa
bb
cc

echo 'aa
bb
aa
bb
cc' |\
awk '{a[$0]++}END{l=asorti(a,b);for(i=1;i<=l;i++)print b[i],a[b[i]]}'
aa 2
bb 2
cc 1

 

 

 
 
屬性 描述
asort  asort對數組進行排序,返回數組長度 
   
   
   
   
   
   
練習1(分析出天天有多少員工離職?有多少員工入職?)
 
awk代碼(test_log_info.awk)
BEGIN{
        today = strftime("%Y-%m-%d-%H", systime());
}
FILENAME == ARGV[1]{ # 第一個文件 舊記錄
        old_user[$1] = $0;
}
FILENAME == ARGV[2]{ # 第二個文件 新紀錄
        new_user[$1] = $0;
}
END{
        log_info = "";
        log_file = log_dir"user_log_info.log."today"";
        for(old_uid in old_user){
                if(new_user[old_uid] == ""){
                        log_info = log_info"leave user:"old_user[old_uid]"\n";
                        delete new_user[new_uid];
                }
        }


        for(new_uid in new_user){
                if(old_user[new_uid] == ""){
                        log_info = log_info"add user:"new_user[new_uid]"\n";
                        delete old_user[new_uid];
                }
        }

        log_info = log_info"old count:"asort(old_user)";new count:"asort(new_user);
        system(" echo '"log_info"' > "log_file);
}

 

分析日誌shell腳本(test_log_info.sh)數據結構

#!/bin/bash

yesterday(){
        yy=`date +%Y` #Year yyyy
        mm=`date +%m` #Month mm
        dd=`date +%d` #Day dd
        if [ $dd = "01" ]
        then
                lm=`expr $mm - 1 `
                if [ $lm -eq 0 ]
                then
                        lm=12
                        yy=`expr $yy - 1 `
                fi
                echo lm=$lm
                case $lm in
                     1|3|5|7|8|10|12) Yesterday=31 ;;
                     4|6|9|11) Yesterday=30 ;;
                     2)
                             if [ ` expr $yy % 4 ` -eq 0 -a `expr $yy % 100 ` -ne 0 -o ` expr $yy % 400 ` -eq 0 ]
                             then Yesterday=29
                             else Yesterday=28
                             fi ;;

                esac
                mm=$lm
                Yesterday=$Yesterday
         else
                Yesterday=`expr $dd - 1 `
         fi

         case $Yesterday
             in 1|2|3|4|5|6|7|8|9) Yesterday='0'$Yesterday
         esac
         case $mm in
               1|2|3|4|5|6|7|8|9) mm='0'$mm ;;
         esac

         Yesterday=$yy"-"$mm"-"$Yesterday"-05"
}
yesterday
Today=`date "+%Y-%m-%d-05"`
TEMP_DIR="/home/rd/zhoubc/bak/"

awk -v "log_dir="$TEMP_DIR -f test_log_info.awk  $BAKDIR""test2.conf.""$Yesterday  $BAKDIR""test2.conf.""$Today

 

調用嵌套的shell文件(test_send.sh)函數

#!/bin/bash
BAKDIR='/home/crontab/send_user/bak/'

source test_log_info.sh

 

調用:post

 

幾個技術點:ui

 

 shell腳本套用(source)——這樣能夠公用變量編碼

source test_log_info.sh

 awk多文件分別處理:

FILENAME == ARGV[1]{}
FILENAME == ARGV[2]{}

 

案例1:統計每一個分類下,樣本的中位數
 
 
數據結構:
下標從1開始計算。第二列爲分類ID,第11類爲月日均pv量。
325	20	230	4918	4	1	64	0	0	64.72	36.9	25	26
803	25	33	249	4	0	74	0	0	4.0	3.5	3	2
841	0	566	8624	11	21	269	1	0	527.57	415.6	1331	825
858	8	498	11569	21	17	477	1	0	1386.29	913.87	2787	2982
1004	6	221	3222	15	7	176	1	0	900.28	673.36	712	458

 

相關代碼:

# $11 是月日均pv量
function ceil(x){
    y = int(x);
    return (x > y ? y + 1 : y)
}
# 取中位數
function get_median(arr){
    len = asort(arr);
    #for(i = 1; i <= len; i++) {
    #    printf("%d\t", arr[i]);
    #}
    #printf("\n");

    mid = ceil(len/ 2);
    if(len%2 == 0){
        return ceil((arr[mid] + arr[mid + 1]) / 2);
    }
    #printf("mid=%d\n", mid);
    return arr[mid];
}

BEGIN{
}
{
    if(!($2 in cardTypeTree)){
        cardTypeTree[$2] = $11;
    } else {
        cardTypeTree[$2] = cardTypeTree[$2]"_"$11;
    }
}
END{
    system("rm -f ./parseType.txt")
    for(key in cardTypeTree){
        split(cardTypeTree[key], array, "_")
        printf("%-10s\t%d\t%-10s\n", key, length(array), get_median(array))
        system("echo '"key"\t"length(array)"\t"get_median(array)"' >> ./parseType.txt")
    }
}

 

執行結果以下:

 

 


 

 
總結
 
   工做中斷斷續續會用到awk腳本,總是用去搜索太麻煩了,故放在這裏,方便往後查閱。若是對你有幫助,就推薦一下!
 
推薦
 
相關文章
相關標籤/搜索