awk的学习笔记

awk(文本三剑客-行处理器+字段分割)

  • 数据流的行处理工具。数据来自stdin或最后一个参数指定文件

  • 逐行处理,对每行都进行模式匹配,如匹配则执行指定命令操作(默认指令为打印当前行)。

  • 优势:拥有自己的编程语法。支持对记录(行)和字段(分割)的处理

  • 记录的概念:一行就是一条记录

  • 字段的概念:一行经过分割符分割,得到多个字段。

格式

  • awk [ -F ‘re’] [‘pattern {action}’] [-f progfile] [filenames]

    # BEGIN{}读取输入前执行
    # END{}全部完成后执行
    awk 'BEGIN{ print ">>>"} {print "ok"} END{print "----"}' /etc/hosts 

指定分隔符

  • -F参数,指定分隔符re,默认为空格或tab,对分割后的每个字段都执行命令

    awk -F":" '{print $1,$3}' /etc/passwd
    #等价于
    cat /etc/passwd | awk 'BEGIN{FS=":"} {print $1,$3}' 
    
    # awk读取一行输入作为"记录",赋值给变量$0
    # awk对这一行分割为多个"字段",存到$1开始的变量中
    # awk按照指定的格式打印,其中逗号会被映射为分隔符OFS,默认为空格
    # awk接着读取下一行,重复上述流程,直到文件结束
    
    
    

行为

  • pattern(匹配模板):可以为正则表达式。满足条件则执行action

  • -f参数,将指定文件内容当作’pattern {action}’

变量

# 变量无需申明,直接使用。默认值为0
# 支持数组,数组的索引可以是个字符串!

内置变量

  • 一般在行前命令中修改;或直接被引用输出

ARGC命令行参数个数(不包括awk的选项和awk的程序内容)。
ARGIND 当前正在处理的ARGV中的文件的索引值(同时处理多个文件时会用到)。
ARGV 命令行参数序列数组,下标从0开始。
CONVFMT 数字转换格式,和C语言中的数字输出格式化类似,默认为"%.6g"。
ENVIRON 当前系统的环境变量。
ERRNO 出错时的错误信息。
FIELDWIDTHS 以空格分隔的字段宽度,如果指定此变量,awk将会用指定的宽度替换变量FS指定的分隔符
FILENAME 当前正在处理的文件名,该变量不能在BEGIN块中使用。
FNR当前处理的记录号。
FS 字段的分隔符,默认为空格。
IGNORECASE 如果该变量设置为非0值,在进行字符串匹配时忽略大小写。
NF 记录中的字段个数。 $NF表示最后一个字段。(好用)
NR 已经读出的记录数。
OFMT 数字的输出格式。
OFS 输出的字段分隔符,默认为空格。
ORS 输出的记录分隔符,默认为新行。
RS 输入记录的分隔符,默认为新行。
RSTART 被match()函数匹配的字符串的起始位置,如果没有匹配则为0(从1开始)。
RLENGTH 被match()函数匹配的字符串的长度。
SUBSEP数组中多个下标的分隔符,默认为"\034"。

# 统计一个文件的行数
cat /etc/passwd | awk '{print NR}'

内置函数

gsub(r,s) 在整个$0中用s代替r
gsub(r,s,t) 在整个t中用s替代r
index(s,t) 返回s中字符串t的第一位置
length(s) 返回s长度
match(s,r) 测试s是否包含匹配r的字符串
split(s,a,fs) 在fs上将s分成序列a
sprint(fmt,exp) 返回经fmt格式化后的exp
sub(r,s) 用$0中最左边最长的子串代替s
substr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分

关系运算符

# ==        字符串的完全相等需要使用
awk -F":" '$NF == "/bin/bash"' /etc/passwd 
# !=        不相等
awk -F":" '$1 != "root"' /etc/passwd

# 数字比较 <,>,<=,>=
# 运算符 =-*/%^(幂)
# 逻辑操作  && || 

#++i:从1开始加,运算在赋值
#i++: 从0开始加,赋值在运算

表达式

  • if

    # {if(表达式){语句;语句;...}}
    # 显示管理员用户姓名
    cat /etc/passwd | awk -F":" '{if($3==0) {print $1 " is administrator"}}' 
    # 统计系统用户数量 
    cat /etc/passwd | awk -F":" '{if($3>=0 && $3<=1000){i++}} END{print i}'
  • for

    # for(i=1;i<=2;i++)
    # for(i in username)
    
    # 每行打印2遍
    awk '{for(i=1;i<=2;i++)
    {print $0}}' /etc/passwd
    # 先将每行的第一个值存到数组,最后再用循环打印出来。为什么打印出来是乱序的?
    cat /etc/passwd | awk -F":" '{username[x++]=$1} END{for(i in username) {print i,username[i]}}'
    
    

经典例子

# 统计各种shell的数量
cat /etc/passwd | awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }'

# 统计nginx日志出现的状态码 
cat access.log | awk '{stat[$9]++} END{for(i in stat){print i,stat[i]}}' 

# 统计当前nginx日志中每个ip访问的数量 
cat access.log | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' 

# 统计某一天的nginx日志中的不同ip的访问量 
cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' 

# 统计nginx日志中某一天访问最多的前10个ip 
cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' |sort -k2 -rn | head -n 2 
# sort:排序,默认升序
UV与PV统计
PV:即访问量,也就是访问您商铺的次数;
UV:即访问人数,也就是有多少人来过您的商铺;需要去重 
# 根据访问IP统计UV 
cat access.log | awk '{print $1}' |sort |uniq -c | wc -l 

# 根具访问ip统计PV 
cat access.log | awk '{print $1}' |wc -l 
# 或者是url 统计PV
cat access.log | awk '{print $7}' |wc -l 

# 查询访问最频繁的URL 
cat access.log | awk '{print $7}'|sort | uniq -c |sort -n -k 1 -r | more 
# 查询访问最频繁的IP 
cat access.log | awk '{print $1}'|sort | uniq -c |sort -n -k 1 -r | more

本文为原创文章,转载请注明出处!

IIR滤波器学习笔记

  • 数字无限冲击响应,输出<==历史输入+当前输入+历史输出(反馈)。也被称为递归滤波器。
  • 本质:来源自模拟滤波器的传输函数。
  • 相位补偿:可以串联全通网络进行相位校正(额外运算量)
  • 选择性越好,则相位非线性越严重
  • 会因为运算精度而累积误差,导致极点偏移,出现系统不稳定(振荡)。
  • 其冲击响应是非对称的,因此相位非线性
  • 计算过程:递归方程

IIR递归方程:

  • 递归系数与频率响应之间可以通过Z变换来转换
  • 一阶IIR可近似于简单的RC滤波器
  • C实现:CMSIS\DSP\Source\FilteringFunctions\arm_biquad_cascade_df1_f32.c

滤波器参数设计

  • 设计思想:设计一个模拟滤波器,并得到它的传输函数,通过”双线性变换”、或”脉冲响应不变法”转换为数字滤波器。如果直接在频域/时域设计,需要求解方程组,通常用软件实现。
  • 难点:在于确定模拟滤波器传输函数H(s),由软件生成/查表。
  • 先确定滤波器类型(巴特沃斯、切比雪夫等)
  • 根据设计参数和滤波器函数确定阶数、传输函数Hs表达式。
  • 如果采用双线性变化法,需要先处理预扭曲问题
  • 使用双线性变换或脉冲响应不变法将Hs求得数字域的差分方程。

    传递函数Hs

    • 传递函数包括零点和极点两组可调因素,对极点的惟一限制是在单位圆内。因此可用较低的阶数获得高的选择性,所用的存储单元少,计算量小,效率高。
    • 必须采用递归结构来配置极点,并保证极点位置在单位圆内,否则自激

biquad型/双二阶(SOS)

 

  • Second-Order Sections(二阶块)。
  • biquad是多个二阶IIR模块块的级联。最为常用IIR设计。
  • 转置结构直接II型biquad(先相加,再延迟,节省延迟器,且能模块化,实用的实现)参数不变,只是运算顺序变化
  • MATLAB生成系数意义:格式为直接II型SOS块参数

固定四阶IIR的C代码实现:

typedef struct
{
    float SOSCoeffs[2*5];      //b0 b1 b2 a1 a2 
    float Gain[2];             //每个抽头的增益
    float Dealy[2*2];          //延迟缓冲state z1 z2
}IIR_context_Td;
void biquad_filter_calc(IIR_context_Td *pCtx,int16_t *InData,int16_t *OutData,uint16_t InNum)
{
    float *pGain = pCtx->Gain;
    float Out,In;
    
    //load param:
    float zdelay11,zdelay12;
    float b10,b11,b12,a11,a12;
    
    zdelay11=pCtx->Dealy[0];
    zdelay12=pCtx->Dealy[1];

    b10=pCtx->SOSCoeffs[0];
    b11=pCtx->SOSCoeffs[1];
    b12=pCtx->SOSCoeffs[2];
    a11=pCtx->SOSCoeffs[3];
    a12=pCtx->SOSCoeffs[4];

    float zdelay21,zdelay22;
    float b20,b21,b22,a21,a22;
    
    zdelay21=pCtx->Dealy[2];
    zdelay22=pCtx->Dealy[3];

    b20=pCtx->SOSCoeffs[5];
    b21=pCtx->SOSCoeffs[6];
    b22=pCtx->SOSCoeffs[7];
    a21=pCtx->SOSCoeffs[8];
    a22=pCtx->SOSCoeffs[9];


    //calc:
    while(InNum--)
    {
        In=(float)*InData++;
        Out=In*b10+zdelay11;
        zdelay11=In*b11+zdelay12+Out*a11;
        zdelay12=In*b12+Out*a12;
        Out= Out*pGain[0];

        In=Out;
        Out=In*b20+zdelay21;
        zdelay21=In*b21+zdelay22+Out*a21;
        zdelay22=In*b22+Out*a22;
        Out= Out*pGain[1];

        *OutData++ = (int16_t)Out;
    }

    //save param:
    pCtx->Dealy[0]=zdelay11;
    pCtx->Dealy[1]=zdelay12;

    pCtx->Dealy[2]=zdelay21;
    pCtx->Dealy[3]=zdelay22;


}

 

 

 

 

 

本文为原创文章,转载请注明出处!