川山甲

追求内心的非常平静!瞬间清空所有的杂念,达到物我两忘!

  博客园  :: 首页  ::  :: 联系 :: 订阅 订阅  :: 管理
  105 随笔 :: 0 文章 :: 1591 评论 :: 82万 阅读
 
 
因为经常做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>读取数组值

{ 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的位置输入你要用的分隔符,如:

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

但,有些特殊情况需要避免,如:

复制代码
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)。 

复制代码
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

 

调用:

 

几个技术点:

 

 shell脚本套用(source)——这样可以公用变量

source test_log_info.sh

 awk多文件分别处理:

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

 

案例1:统计每个分类下,样本的中位数
 
 
数据结构:
下标从1开始计算。第二列为分类ID,第11类为月日均pv量。
1
2
3
4
5
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

 

相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# $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脚本,老是用去搜索太麻烦了,故放在这里,方便日后查阅。如果对你有帮助,就推荐一下!
 
推荐
 
posted on   川山甲  阅读(1891)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示