测试小站: 处理网 回收帮 培训网 富贵论坛 老富贵论坛

AWK 简单入门教程

  awk是什么

  awk其名称来自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。 实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。 它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

  简单使用

  首先介绍几个简单的实例,以便大家有个直观的了解。 有如下的基金历史数据,存储在文件000962.txt内,共有20行数据,每行有4个字段。 这里列出了前9行的数据。

  1 2021-12-25 1.2366 1.2366

  2 2021-12-24 1.2296 1.2296

  3 2021-12-23 1.2324 1.2324

  4 2021-12-22 1.2454 1.2454

  5 2021-12-21 1.2351 1.2351

  6 2021-12-18 1.2218 1.2218

  7 2021-12-17 1.2247 1.2247

  8 2021-12-16 1.1965 1.1965

  9 2021-12-15 1.1906 1.1906

  如果我们想取得第3列数据大于1.2的结果,可以如下处理

  $ awk '$3>1.2' 000962.txt

  1 2021-12-25 1.2366 1.2366

  2 2021-12-24 1.2296 1.2296

  3 2021-12-23 1.2324 1.2324

  4 2021-12-22 1.2454 1.2454

  5 2021-12-21 1.2351 1.2351

  6 2021-12-18 1.2218 1.2218

  7 2021-12-17 1.2247 1.2247

  15 2021-12-07 1.2080 1.2080

  17 2021-12-03 1.2028 1.2028

  那我们如果只需要返回日期和基金净值呢:

  $ awk '$3>1.2{print $2,$3}' 000962.txt

  2021-12-25 1.2366

  2021-12-24 1.2296

  2021-12-23 1.2324

  2021-12-22 1.2454

  2021-12-21 1.2351

  2021-12-18 1.2218

  2021-12-17 1.2247

  2021-12-07 1.2080

  2021-12-03 1.2028

  如果我们需要在每行前加上行号的话,可以这样:

  $ awk 'BEGIN{NM=0;} $3>1.2{NM+=1;print NM,$2,$3}' 000962.txt

  1 2021-12-25 1.2366

  2 2021-12-24 1.2296

  3 2021-12-23 1.2324

  4 2021-12-22 1.2454

  5 2021-12-21 1.2351

  6 2021-12-18 1.2218

  7 2021-12-17 1.2247

  8 2021-12-07 1.2080

  9 2021-12-03 1.2028

  记录和字段

  从上面几个例子里,有涉及到记录和字段的概念,如果你已经很熟悉了,此段可以略过。

  一条记录可以粗略的理解为一行。字段是一行里彼此分开的数据段,每一段就是一个字段值。 比如如下数据:

  AAA 111

  BBB 222

  CCC 333

  DDD 444

  我们称为有4条记录,每条记录有3个字段。 这里有一个规则,就是我们默认为记录与记录之间是通过换行符分割的,字段与字段之间是通过空格分割的。

  所以, 只要改变其中的一个规则,我们可以把上述数据表示为一下格式:

  AAA+111

  BBB+222

  CCC+333

  DDD+444

  这里采用了默认的记录分隔符 --- 换行符,而没有采用默认的字段分隔符 --- 空格,而是使用了加号(+),规则是我们自己定义的。

  所以对于上面提到的,『一条记录可以粗略的理解为一行』,这里的粗略就是指默认的记录分隔符---换行符。 当记录分隔符不是换行符的情况时,一行数据可能代表的就是多条记录,这取决于我们对于数据的理解。

  AAA+111|BBB+222|CCC+333|DDD+444

  这个也可以表示成上述数据的第三种格式。 如果我们需要把第三种数据输出成第一种,也是可以做到的。

  $ echo 'AAA+111|BBB+222|CCC+333|DDD+444'|awk 'BEGIN{FS=+";RS="|"}{print $1, $2}'

  AAA 111

  BBB 222

  CCC 333

  DDD 444

  这里我们使用到了AWK支持的两个参数FS和RS。FS是field separator的缩写,称为字段分隔符。 RS是recod separator的缩写,称为记录分隔符。

  所以对于数据的解读,取决于我们对于记录分隔符和字段分隔符的定义。 只需要把规则告诉AWK,它就能给你想要的。

  在AWK的处理过程中,我们可以通过$0来表示当前记录,用$1代表第一个字段,一直到$n,n就是当前记录的字段总数。

  awk处理流程

  awk处理的大致流程,就是以记录分隔符将文本切分成记录, 然后再对每条记录以字段分隔符为准,切分成字段,再把这些值转换成变量给到程序处理。

  经过AWK的处理处理之后,$0代表的就是整个单条的记录,$1~$n代表的就是当前行的字段,$n表示当前行的最后一个字段值。 AWK重复的执行代码,输入就是每行,一直到最后一条记录。

  $0的值是变动的,指示的是当前的行,在当前行上你是没有办法直接拿到上一条数据的,除非你自己保存了上行数据; 同样你也是没有办法拿到下一条数据的,你能做的就是处理完这条记录或跳过这条,等待下一条的来临。

  除了按记录处理流程,awk还定义了BEGIN和END块。 BEGIN块在处理所有记录之前执行,END块在处理完所有记录后执行。

  $ awk 'BEGIN{print "beggin...";NM=0;SUM=0;}{NM+=1;SUM+=$3;print;} END{print "average is:",SUM/NM}' 000962.txt

  beggin...

  1 2021-12-25 1.2366 1.2366

  2 2021-12-24 1.2296 1.2296

  ... ... ... ...

  19 2021-12-01 1.1838 1.1838

  20 2021-11-30 1.1784 1.1784

  average is: 1.20086

  为了避免输出结果占用过多的篇幅,中间部分用省略号做了替代。

  第二份数据,tcp连接报告。

  tcp4 0 0 192.168.1.103.50660 17.250.120.76.443 FIN_WAIT_1

  tcp4 0 0 192.168.1.103.50655 74.125.23.138.443 SYN_SENT

  tcp4 0 0 192.168.1.103.50654 74.125.23.139.443 SYN_SENT

  tcp4 0 0 192.168.1.103.50653 74.125.23.100.443 SYN_SENT

  tcp4 0 0 192.168.1.103.50652 74.125.23.100.443 SYN_SENT

  tcp4 0 0 192.168.1.103.50646 202.108.249.252.80 CLOSE_WAIT

  tcp4 0 0 192.168.1.103.50645 202.108.249.252.80 CLOSE_WAIT

  tcp4 0 0 192.168.1.103.50644 202.108.249.252.80 CLOSE_WAIT

  tcp4 0 0 192.168.1.103.50643 202.108.249.252.80 CLOSE_WAIT

  tcp4 0 0 192.168.1.103.50642 111.202.60.47.80 LAST_ACK

  tcp4 0 0 192.168.1.103.50547 198.41.215.67.80 LAST_ACK

  tcp4 0 0 192.168.1.103.49779 209.20.75.76.80 CLOSE_WAIT%

  字段的处理

  获取所有的本地打开的端口以及端口的连接状态。

  $ cat ./tcp.txt|awk '{print substr($4,15), $6;}'

  50660 FIN_WAIT_1

  50655 SYN_SENT

  50654 SYN_SENT

  50653 SYN_SENT

  50652 SYN_SENT

  50646 CLOSE_WAIT

  50645 CLOSE_WAIT

  50644 CLOSE_WAIT

  50643 CLOSE_WAIT

  50642 LAST_ACK

  50547 LAST_ACK

  49779 CLOSE_WAIT

  表达式和语句

  AWK的程序由两部分组成,分为模式匹配和动作表达式,即pattern {action}组成。 省略pattern表示匹配所有行,{action}是可以省略的,表示打印整个行。但是不能同时都省略。

  AWK会对匹配表达式结果为真的行,执行对应的动作表达式。

  pattern-action之间通过换行或分号进行分割。

  action表示的是一个语句序列,一个语句可以由以下部分组成:

  [ ] 表示可选

  判断语句: if(表达式) 语句1 [ else 语句2 ]循环语句: while(表达式) 语句for: for(表达式; 表达式; 表达式) 语句for-in: for(变量 in 数组变量) 语句do-while: do 语句 while(表达式)中断: break 只能用在 for、for-in、while、do-while里继续: continue 只能用在 for、for-in、while、do-while里语句: { [语句] } 注意这里有左右大括号表达式: 如 age=33打印语句: print [ 表达式列表 ] [ > 表达式 ]格式化: printf 格式串 [ , 表达式类别 ] [ 表达式 ]返回值: return [表达式]next: next 忽略当前行后续匹配nextfile: nextfile 跳过当前文件剩余行,打开下一个文件,并从头开始删除数组元素: delete 数组名[表达式] 删除数组元素删除数组: delete 数组名exit: exit [表达式]

  语句之间可以通过换行符、分号、括号进行分割。

  获取列表中的tcp状态,并且去掉CLOSE_WAIT,就可以使用以上的delete语句。

  cat ./tcp.txt|awk '{all[$6]++}{delete all["CLOSE_WAIT"]} END{for(st in all){print st, all[st];}}'

  FIN_WAIT_1 1

  SYN_SENT 4

  LAST_ACK 2

  模式匹配

  AWK是否执行一个动作,取决于输入记录是否和Pattern匹配。常见的Pattern有:

  /regexp/ 正则表达式, 当输入记录匹配正则表达式时,执行相应动作表达式 当表达式的值不为0或不为空(作为字符串)时, 匹配结果为真,执行相应动作模式1, 模式2 这是一对Pattern, 它匹配一个范围, 表示从匹配模式1开始直到匹配2所有的记录BEGIN和END 这是两个特殊的Pattern, 分表表示文件的第一行被读之前和最后一行执行之后。Pattern为空时,匹配所有的记录

  # 匹配第一个字段包含2和3的所有的记录

  $ cat ./000962.txt|awk '$1 ~ /[23]+/'

  2 2021-12-24 1.2296 1.2296

  3 2021-12-23 1.2324 1.2324

  12 2021-12-10 1.1685 1.1685

  13 2021-12-09 1.1719 1.1719

  20 2021-11-30 1.1784 1.1784

  # 匹配第一个字段不包含2和3的所有记录

  $ cat ./000962.txt|awk '$1 !~ /[23]+/'

  1 2021-12-25 1.2366 1.2366

  4 2021-12-22 1.2454 1.2454

  5 2021-12-21 1.2351 1.2351

  6 2021-12-18 1.2218 1.2218

  7 2021-12-17 1.2247 1.2247

  8 2021-12-16 1.1965 1.1965

  ... ... 省略

  18 2021-12-02 1.1778 1.1778

  19 2021-12-01 1.1838 1.1838

  # 打印以第11到14条的记录

  cat ./000962.txt|awk '/^11/,/14/'

  11 2021-12-11 1.1599 1.1599

  12 2021-12-10 1.1685 1.1685

  13 2021-12-09 1.1719 1.1719

  14 2021-12-08 1.1774 1.1774

  内置常量CONVFMTFS 字段分隔符,值是一个正则表达式NF 当前记录的字段总个数NR 当前记录的顺序号FNR 当前记录位于当前文件的顺序号,处理多个文件的时候有用FILENAME 当前文件名RS 记录分隔符,默认为换行符OFS 指定以怎样的分隔符为输出数据的字段分隔符,默认为空格ORS 输出记录分隔符,默认为换行OFMT 输出顺序号的格式,默认为 0.6gSUBSEPARGCARGVENVIRON内置函数length(s) 把参数值当做字符串所占有的长度,如果没有指定参数默认为当前记录的总长度srand 设置随机谁的种子rand 返回0~1之间的一个随机数int 转换字符串成数值类型gsub(r,s) 在整个$0中用s替代rgsub(r,s,t) 在整个t中用s替代rindex(s,t) 返回s中字符串t的第一位置match(s,r) 测试s是否包含匹配r的字符串split(s,a,fs) 在fs上将s分成序列asprint(fmt,exp) 返回经fmt格式化后的expsub(r,s) 用$0中最左边最长的子串代替ssubstr(s,p) 返回字符串s中从p开始的后缀部分substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分system(cmd)tolower(str)toupper(str)

  原文:juejin/entry/579f18112e958a00665eab05

posted @ 2021-12-10 11:26  linjingyg  阅读(330)  评论(0)    收藏  举报