感谢支持
我们一直在努力

Linux awk命令使用详解

简单介绍一下,awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大,这是我们玩linux的必备基本功,若要对其身世有更详尽的了解,自行搜索即可。对于工具的知识,笔者尽量将每个知识点的简要说明,并给出实例。
 
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
 
用法:
awk [options] ‘scripts’ file1,file2…
awk [options] ‘pattern {action}’ file1,file2…
 
options是awk的支持的选项,譬如-F -v等; scripts是其处理脚本,包含模式pattern和动作action(模式和动作的关系一般为,模式负责确定有效字段,动作负责对其处理)
 
一、print的简单使用
 
创建一个简单的测试文件如下:

  1. [root@mos download]# cat demo.txt
  2. Welcome to mos blog.
  3. This is a test file.

例:打印整行: $0

  1. [root@mos download]# awk ‘{print $0}’ demo.txt
  2. Welcome to mos blog.
  3. This is a test file.

例:打印每行的最后一个字段: $NF

  1. [root@mos download]# awk ‘{print $NF}’ demo.txt
  2. blog.
  3. file.

例:打印第二个字段: $2

  1. [root@mos download]# awk ‘{print $2}’ demo.txt
  2. to
  3. is

例:打印每行的倒数第二个字段,并在其后打印OK

  1. [root@mos download]# awk ‘{print $(NF-1),”OK”}’ demo.txt
  2. mos OK
  3. test OK

例:打印行号

  1. [root@mos download]# awk ‘{print NR,$0}’ demo.txt
  2. 1 Welcome to mos blog.
  3. 2 This is a test file.

例:打印当前系统环境变量的某个特定值,譬如路径,下面俩输出一样

  1. [root@mos download]# awk ‘{print ENVIRON[“USER”];}’ demo.txt
  2. root
  3. root
  4. [root@mos download]# awk ‘BEGIN{print ENVIRON[“PATH”];}’
  5. /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
  6. PS:后面的文件只是为了让print成功执行,BEGIN是执行前可以输出的数据,常用作写为报告标题和测试输出,其内容不能获得与文件修改操作有关的变量,后面会说到;

例:awk的默认分隔符为空格,而有些文本字以其他字符为分隔符,以下两例相同

  1. [root@mos download]# awk -F: {‘print $1,$NF’} /etc/passwd|tail -1
  2. mos1 /bin/bash
  3. [root@mos download]# awk -v FS=: ‘{print $1,$NF}’ /etc/passwd|head -1
  4. root /bin/bash

例:修改输出分隔符号,特殊字符需转义,如下几例:

  1. [root@mos download]# awk -v OFS=. ‘{print $1,$NF}’ demo.txt
  2. Welcome.blog.
  3. This.file.
  4. [root@mos download]# awk -v OFS=“~”‘{print $1,$NF}’ demo.txt
  5. Welcome~blog.
  6. This~file.
  7. [root@mos download]# awk -v OFS=\” ‘{print $1,$NF}’ demo.txt
  8. Welcome”blog.
  9. This”file.
  10. [root@mos download]# awk -v OFS=9 ‘{print $1,$NF}’ demo.txt
  11. Welcome9blog.
  12. This9file.
  13. [root@mos download]# awk -v OFS=XXXX ‘{print $1,$NF}’ demo.txt
  14. WelcomeXXXXblog.
  15. ThisXXXXfile.
  16. PS: 若在print输出字段的之间不写逗号,则输出分隔符无效,输出的结果会直接连在一起

awk中有许多默认的变量,例如之前列出的:$1~$n、$0、FS、OFS等。下图为awk内置变量表:

  1. 属性 说明
  2. $0 当前记录(作为单个变量)
  3. $1~$n 当前记录的第n个字段,字段间由FS分隔
  4. FS 输入字段分隔符 默认是空格
  5. NF 当前记录中的字段个数,就是有多少列
  6. NR 已经读出的记录数,就是行号,从1开始
  7. RS 输入的记录他隔符默 认为换行符
  8. OFS 输出字段分隔符 默认也是空格
  9. ORS 输出的记录分隔符,默认为换行符
  10. ARGC 命令行参数个数
  11. ARGV 命令行参数数组
  12. FILENAME 当前输入文件的名字
  13. IGNORECASE 如果为真,则进行忽略大小写的匹配
  14. ARGIND 当前被处理文件的ARGV标志符
  15. CONVFMT 数字转换格式 %.6g
  16. ENVIRON UNIX环境变量
  17. ERRNO UNIX系统错误消息
  18. FIELDWIDTHS 输入字段宽度的空白分隔字符串
  19. FNR 当前记录数
  20. OFMT 数字的输出格式 %.6g
  21. RSTART 被匹配函数匹配的字符串首
  22. RLENGTH 被匹配函数匹配的字符串长度
  23. SUBSEP \034
  24. 声明一下:由于许多变量笔者亦不怎么常用,因此笔者此处未全部列出。

二、printf的使用

格式:
printf format1,format2…, item1,item2…
PS:与print不同的是,首先,其多了个f;然后,其不会自动换行,而且还需要对每个字段指定输出格式。听起来很麻烦,用起来很爽的。

例:左右对齐打印输出,中间的符号笔者自己添加的,双引号和反斜杠前使用反斜杠转义即可;

  1. [root@linuxidc download]# awk ‘{printf “%15s->%10s\n”,$1,$NF}’ demo.txt
  2. Welcome-> blog.
  3. This-> file.
  4. [root@linuxidc download]# awk ‘{printf “%-15s#%10s\n”,$1,$NF}’ demo.txt
  5. Welcome # blog.
  6. This # file.
  7. [root@linuxidc download]# awk ‘{printf “%-15s’\%10s\n”,$1,$NF}’ demo.txt
  8. Welcome ‘ blog.
  9. This ‘ file.
  10. PS:一个单引号的写法太贱了,还有%,得写三个..各种无力吐槽

例:以特定格式输出passwd字符

  1. [root@linuxidc download]# awk -F: ‘{printf “%-15s->%10s ->%20s\n”,$1,$(NF-3),$NF}’ /etc/passwd|head -2
  2. root -> 0 -> /bin/bash
  3. bin -> 1 -> /sbin/nologin

例:以几种不同的计数方法打印一些数字

  1. [root@linuxidc ~]# awk ‘BEGIN{n1=111.29;n2=-3.444;n3=5.6789;printf(“%.2f,%.2u,%.2g,%X,%o\n”,n1,n2,n3,n1,n1);}’
  2. 111.29,18446744073709551613,5.7,6F,157

printf的格式都以%开头,后跟字符:具体如下:

  1. 格式符 说明
  2. %d 十进制有符号整数
  3. %u 十进制无符号整数
  4. %f 浮点数
  5. %s 字符串
  6. %c 显示字符的ASCII码
  7. %p 指针的值
  8. %e 科学技术法显示数值
  9. %x %X 无符号以十六进制表示的整数
  10. %o 无符号以八进制表示的整数
  11. %g %G 以科学计数法或浮点数的格式显示数值
  12. %% 显示其自身
  13. 修饰符:
  14. -: 左对齐 这个好使,下面俩试了试,笔者没试出啥感觉..
  15. +: 显示数值符号
  16. N: 显示

三、输出重定向
awk的输出结果可以直接使用输出重定向和管道,其作用和命令结束再次使用重定向和管道的效果类似,笔者在此不长篇叙述,仅作简单示范和介绍:
print items > output_file
print items >> output_file
print items | command

特殊文件描述符:
/dev/stdin: 标准输入
/dev/sdtout: 标准输出
/dev/stderr: 错误输出
/dev/fd/N: 某特定文件描述符,如/dev/stdin就相当于/dev/fd/0;

例:将结果输出到当前目录下的某个文本中;下两例效果一样

  1. # awk -F: ‘{printf “%-15s->%+10s->%20s\n”,$1,$(NF-2),$NF > “test.txt” }’ /etc/passwd
  2. # awk -F: ‘{printf “%-15s->%+10s->%20s\n”,$1,$(NF-2),$NF }’ /etc/passwd > test1.txt

 

awk的操作符,这些操作符和shell编程中的意思大都一致,因此不做详细解说,又因为单单一个的实例难以表达,笔者下方列出完之后,实例部分大都混合使用,笔者会一一说明。

一、算数操作符

  1. 操作符 描述
  2. -x 负值
  3. +x 转换为数值
  4. x^y 次方
  5. x**y 次方
  6. x*y 乘法
  7. x/y 除法
  8. x+y 加法
  9. x-y 减法
  10. x%y 取余

二、字符串操作符:
直接将print输出的结果之间不适用逗号或自定义OFS,即可,其实这是一个空值
例如:以下两例效果一样

  1. [root@linuxidc download]# awk ‘{print $1 $2}’ demo.txt
  2. Welcometo
  3. Thisis
  4. [root@linuxidc download]# awk ‘{print $1$2}’ demo.txt
  5. Welcometo
  6. Thisis

三、赋值操作符

  1. 操作符 描述
  2. = 赋值操作符
  3. += 赋值加操作符
  4. -= 赋值减操作符
  5. *= 赋值乘操作符
  6. /= 赋值除操作符
  7. %= 赋值求余操作符
  8. ^= 赋值求幂操作符
  9. **= 赋值求幂操作符
  10. PS:需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代;

四、布尔值
awk中,任何非0值或非空字符串都为真,反之就为假;
五、比较操作符

  1. 操作符 描述
  2. > 大于
  3. < 小于
  4. >= 大于等于
  5. <= 小于等于
  6. == 等于
  7. != 不等于
  8. ~ 匹配
  9. !~ 匹配取反

六、表达式间的逻辑关系符
&& :逻辑与
|| :逻辑或

例:
打印系统上uid大于等于500且以m开头的行的首字段;&&与

  1. [root@linuxidc ~]# awk -F: ‘$3>=500 && $1 ~ /^m/{print $1}’ /etc/passwd
  2. linuxidc
  3. linuxidc1

打印系统上uid大于等于500或以v开头的行的首字段;||:或

  1. [root@linuxidc ~]# awk -F: ‘$3>=500 || $1 ~/^v/{print $1}’ /etc/passwd
  2. vcsa
  3. nfsnobody
  4. student
  5. visitor
  6. linuxidc
  7. linuxidc1

打印系统上uid大于500的以v和m开头的行的首字段:

  1. [root@linuxidc ~]# awk -F: ‘$3>=500 && $1 ~/^m/|| $3>=500 && $1 ~/^v/{print $1}’ /etc/passwd
  2. visitor
  3. linuxidc
  4. linuxidc1

七、条件表达式
selector?if=true=exp:if=false=exp
selector是条件,例如使用index函数判断一个变量中有无特定字符;有无则输出特定表达式if=true=exp:if=false=exp,如下例:

在变量值中做查找判断,index是awk的内置函数

  1. [root@linuxidc ~]# awk ‘BEGIN{msg=”My name is linuxidc!”;print index(msg,”linuxidc”)?”ok”:”no”;}’
  2. ok
  3. [root@linuxidc ~]# awk ‘BEGIN{msg=”My name is linuxidc!”;print index(msg,”AAA”)?”ok”:”no”;}’
  4. no

八、函数调用
function_name (parament1,parament2…)
用法
…您看上面,index函数的例子…对头,就那么用的。关于函数和以上的例子,在awk的模式介绍完后,基本都会有.

awk的模式
上面的关于逻辑运算符&&和||的例子中,已经用到了awk的模式,其以m和v开头的和大于等于500的运算,分别是表达式expression和正则表达式regexp,需要说明的是,其还支持取反和模糊匹配等,如下例及各种例:

例:打印/etc/passwd中以root开头的相应字段和非以root开头的相应字段

  1. [root@linuxidc download]# awk -F: ‘/^root/{print $1,$NF}’ /etc/passwd
  2. root /bin/bash
  3. [root@linuxidc download]# awk -F: ‘!/^root/{print $1,$NF}’ /etc/passwd|head -2
  4. bin /sbin/nologin
  5. daemon /sbin/nologin

例:第三个字段有0的打印,和仅为0的,模糊匹配和精确匹配

  1. [root@linuxidc ~]# awk -F: ‘$3~0{print}’ /etc/passwd
  2. root:x:0:0:root:/root:/bin/bash
  3. uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
  4. ………
  5. [root@linuxidc ~]# awk -F: ‘$3==0{print}’ /etc/passwd
  6. root:x:0:0:root:/root:/bin/bash

除了上面用到的表达式,还有ranges和BEGIN/END,其分别为范围匹配和特殊模式;例子如下:

例:打印从visitor开头的行到linuxidc1开头的行中的所有行:ranges范围匹配

  1. [root@linuxidc ~]# awk ‘/^visitor/,/^linuxidc1/{print}’ /etc/passwd
  2. visitor:x:501:501::/home/visitor:/bin/bash
  3. linuxidc:x:502:502::/home/linuxidc:/bin/bash
  4. linuxidc1:x:503:503::/home/linuxidc1:/bin/bash

例:打印结果添加标题和结束语:BEGIN和END的使用

  1. [root@linuxidc download]# awk -F: ‘BEGIN {print “Name\tShell”}{print $1,”\t”,$NF}END{print “—End—“}’ /etc/passwd
  2. Name Shell
  3. root /bin/bash
  4. …………….
  5. mysql /bin/bash
  6. —End—

例:在条件执行之前,先打印标题字段,并在结束后,打印结束字段

  1. [root@linuxidc ~]# awk -F: ‘BEGIN{print “Username UID”}$3>=500 && $1 ~ /^m/{printf “%-15s%s\n”,$1,$3}END{print “—END—“}’ /etc/passwd
  2. Username UID
  3. linuxidc 502
  4. linuxidc1 503
  5. —END—
  6. [root@linuxidc ~]# awk -F: ‘BEGIN{print “Username UID”}{printf “%-15s%s\n”,$1,$3}END{print “—END—“}’ /etc/passwd 去掉条件匹配,打印所有.

例:统计有某个关键字的行的总行数,并输出BEGIN和END信息,其中count++表示:每遇一个相同的则加1,最后输出总数

  1. [root@linuxidc download]# awk -F: ‘BEGIN {count=0}$NF ~/nologin/ {count++}END{print “Nologin number is:”,count}’ /etc/passwd
  2. Nologin number is: 30

例:使用BEGIN也可以直接显示字符串

  1. [root@linuxidc ~]# awk ‘BEGIN{print “a””b”}’
  2. ab
  3. [root@linuxidc ~]# awk ‘BEGIN{print “a”,”b”}’
  4. a b
  5. [root@linuxidc ~]# awk -v OFS=\~ ‘BEGIN{print “a”,”b”}’
  6. a~b

例:BEGIN也可以给字段分隔符变量赋值

  1. [root@linuxidc download]# awk ‘BEGIN{FS=”:”}{print $1}’ /etc/passwd|head -2
  2. root
  3. bin

例:打印判断系统用户和普通用户输出:if条件判断和多条件判断

  1. [root@linuxidc download]# awk -F: ‘{if ($3<=499)print $1,”Sys User”;else print $1,”Common User.”}’ /etc/passwd
  2. root Sys User
  3. ………..
  4. linuxidc1 Common User.
  5. mysql Sys User
  6. [root@linuxidc download]# awk -F: ‘{if($3==0){print $1,”Admin User”;}else if($3>0 && $3<=499){print $1,”Sys User”;}else{print $1,”Comm User”}}’ /etc/passwd
  7. root Admin User
  8. bin Sys User
  9. ………….
  10. nfsnobody Comm User
  11. …………
  12. oprofile Sys User
  13. ………………..
  14. linuxidc1 Comm User
  15. mysql Sys User

例:使用while打印/etc/passwd中非root且非空行的前四个字段:while语句

  1. [root@linuxidc download]# awk -F: ‘$1!~/root/ && $1 !~/^$/{i=1;while(i<=4){print $i;i++}}’ /etc/passwd|head -4
  2. bin
  3. x
  4. 1
  5. 1

例:打印不包含root行的每行的奇数和偶数字段:while和for循环

  1. # awk -F: ‘$1!~/root/{i=1;while(i<=NF){print $i;i+=2}}’ /etc/passwd while奇
  2. # awk -F: ‘$1!~/root/{i=2;while(i<=NF){print $i;i+=2}}’ /etc/passwd while偶
  3. # awk -F: ‘{for(i=1;i<=NF;i+=2) print $i}’ /etc/passwd for
  4. # awk -F: ‘{for(i=2;i<=NF;i+=2) print $i}’ /etc/passwd for

例:数组的引用,下标可以是字符串,但需要双引号,数字则不需要

  1. [root@linuxidc download]# awk ‘BEGIN{A[10]=”hello”;A[15]=”world”;print A[10],A[15]}’
  2. hello world
  3. [root@linuxidc download]# awk ‘BEGIN{A[“m”]=”hello”;A[“n”]=”world”;print A[“m”],A[“n”]}’
  4. hello world

例:数组的遍历

  1. [root@linuxidc download]# awk ‘BEGIN{A[“m”]=”hello”;A[“n”]=”world”;for(B in A)print A[B],”OK”}’
  2. hello OK
  3. world OK

例:遍历环境变量关联数组,并以其下标加等号打印出:数组和环境变量

  1. [root@linuxidc download]# awk ‘BEGIN{for(k in ENVIRON){print k”=”ENVIRON[k],”OK”;}}’
  2. AWKPATH=.:/usr/share/awk OK
  3. OLDPWD=/root OK
  4. ………

例:统计以tcp开头网络状态的连接数:模式匹配、for循环和数组

  1. [root@linuxidc download]# netstat -ant|awk ‘$1~/tcp/{S[$NF]++}END{for (A in S) printf “%-15s:%s\n”,A,S[A]}’
  2. LISTEN :11
  3. ESTABLISHED :2

例:统计不为空的用户的shell数量

  1. [root@linuxidc download]# awk -F: ‘$NF!~/^$/{S[$NF]++}END{for (A in S)print A,S[A]}’ /etc/passwd
  2. /bin/sync 1
  3. /bin/bash 6
  4. /sbin/nologin 30
  5. /sbin/halt 1
  6. /sbin/shutdown 1

例:打印100以内的加法,使用while和do~while

  1. [root@linuxidc download]# awk ‘BEGIN{res=0;i=0;do{res+=i;i++;}while(i<=100)print res;}’
  2. 5050
  3. [root@linuxidc download]# awk ‘BEGIN{while(i<=100){res+=i;i++;}print res;}’
  4. 5050

例:awk执行计算的速度是shell的近40倍

  1. [root@linuxidc ~]# time(awk ‘BEGIN{res=0;for(i=0;i<=10000;i++){res+=i;}print res;}’)
  2. 50005000
  3. real 0m0.003s
  4. user 0m0.001s
  5. sys 0m0.001s
  6. [root@linuxidc ~]# time(res=0;for i in $(seq 10000);do res=$(($res+i));done;echo $res;)
  7. 50005000
  8. real 0m0.114s
  9. user 0m0.097s
  10. sys 0m0.011s

例:统计apache常规日志的IP的访问次数,最多的前5个

  1. # awk ‘{IP[$1]++}END{for(A in IP)print IP[A],A}’ access_log|sort -rn|head -5

awk一些内部函数的使用

例:取1000以内的随机数

  1. [root@linuxidc download]# awk ‘BEGIN{srand();fr=int(1000*rand());print fr;}’
  2. 796
  3. [root@linuxidc download]# awk ‘BEGIN{srand();fr=int(1000*rand());print fr;}’
  4. 224

例:gsub的使用,将lab变量的任意数字替换为–demo–后并输出

  1. [root@linuxidc ~]# awk ‘BEGIN{lab=”2My name is linuxidc2012.”;gsub(/[0-9]+/,”–demo–“,lab);print lab}’
  2. –demo–My name is linuxidc–demo–.

例:正则表达式匹配,match函数的使用

  1. [root@linuxidc download]# awk ‘BEGIN{res=”My name is linuxidc!”;print match(res,/[0-9]+/)?”ok”:”no”;}’
  2. no
  3. [root@linuxidc download]# awk ‘BEGIN{res=”My name is linuxidc88!”;print match(res,/[0-9]+/)?”ok”:”no”;}’
  4. ok

例:截取字符串,substr的使用,从第四个字符,截取四个字符长度

  1. [root@linuxidc ~]# awk ‘BEGIN{info=”My Name is linuxidc!”;print substr(info,4,4);}’
  2. Name

例:字符串分割,split和length的使用,先打印总长度,然后打印每个数组中每个值和其下标

  1. [root@linuxidc ~]# awk ‘BEGIN{test=”My name is linuxidc.”;split(test,Ary,” “);for(l in Ary){print l,Ary[l];}print length(Ary),”Str Len”;}’
  2. 4 linuxidc.
  3. 1 My
  4. 2 name
  5. 3 is
  6. 4 Str Len

例:打开外部文件,close函数的用法,getline打开管道,将读取内容送给print

  1. [root@linuxidc ~]# awk -v FS=: ‘BEGIN{while(“cat /etc/passwd”|getline){print $1;};close(“/etc/passwd”);}’|head -3
  2. root
  3. bin
  4. daemon

例:逐行读取外部文件,getline用法,其实上一个也列出了getline的使用方法.

  1. [root@linuxidc ~]# awk ‘BEGIN{while(getline<“/etc/passwd”){print $0,”OK”;};close(“/etc/passwd”);}’|tail -3
  2. linuxidc:x:502:502::/home/linuxidc:/bin/bash OK
  3. linuxidc1:x:503:503::/home/linuxidc1:/bin/bash OK
  4. mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash OK

例:调用外部应用程序

  1. [root@linuxidc download]# awk ‘BEGIN{D=system(“df -hP”);print D;}’
  2. Filesystem Size Used Avail Use% Mounted on
  3. /dev/mapper/My_vg-lv_root 9.7G 3.1G 6.2G 33% /
  4. /dev/mapper/My_vg-lv_home 496M 19M 452M 4% /home
  5. /dev/sda1 99M 13M 82M 13% /boot
  6. tmpfs 1014M 0 1014M 0% /dev/shm
  7. /dev/hdc 3.3G 3.3G 0 100% /rhel_dvd

例:获取shell变量

  1. [root@linuxidc ~]# Out=“My name is linuxidc.”
  2. [root@linuxidc ~]# echo|awk ‘{print res}’ res=“$Out”
  3. My nameis linuxidc.
  4. [root@linuxidc ~]# echo|awk -v res1=“$Out”‘BEGIN{print res1}’
  5. My nameis linuxidc.
  6. [root@linuxidc ~]# echo|awk -v res1=“$Out”‘{print res1}’
  7. My nameis linuxidc.

例:时间函数mktime、strftime和system的使用:输出一个指定时间,两个时间差,指定时间跟当前时间差

  1. [root@linuxidc download]# awk ‘BEGIN{Tim=mktime(“2012 12 21 23 59 59”);print strftime(“%c”,Tim);}’
  2. Fri 21 Dec 2012 11:59:59 PM CST
  3. [root@linuxidc download]# awk ‘BEGIN{Time=mktime(“2012 12 21 23 59 59”);Time1=mktime(“2012 12 21 23 59 01”);print Time-Time1;}’
  4. 58
  5. [root@linuxidc download]# awk ‘BEGIN{Time=mktime(“2012 12 21 23 59 59”);Time1=systime();print Time1-Time;}’
  6. 535294

 

到此为止,以上笔者缩写,若都可以理解,并自己改写成所需要的,基本上awk的常规使用,应是没问题了,当然,笔者亦未全部说完相关知识点,每个知识,若要学透,皆非朝夕之事,一起努力吧!

赞(0) 打赏
转载请注明出处:服务器评测 » Linux awk命令使用详解
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏