Jusene's Blog

awk使用详解

字数统计: 2.5k阅读时长: 11 min
2017/03/10 Share

AWK

熟悉linux系统的都知道,linux文本处理三剑客,grep,sed,awk。这三个工具中属awk最难理解与使用,以前自己也是只会基本使用,这里想总结下awk的基本使用,为了更好的理解与使用awk。

首先awk是一款文本报告生成工具,它不仅是linux也是任何环境中现有的功能最强大的数据处理引擎,它自成一套编程数据操作语言,效仿c语言设计理念,所以在语法上会与c语言很相近,awk提供了其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。

最简单地说, awk是一种用于处理文本的编程语言工具。awk在很多方面类似于 shell 编程语言,尽管awk具有完全属于其本身的语法,操作可能会很复杂,但命令的语法始终是:

1
awk [opotion] 'program' file ...

这里的program包括PATTERN{ACTION STATEMENTS}

选项

  • -F:输入数据字段的分隔符
  • -v var=value:自定义变量

常见的及常用的也就这两个选项了,示例:

1
~]#awk -F':' -v user='用户名' '{print user,$1}' /etc/passwd                  
2
用户名 root
3
用户名 bin
4
用户名 daemon
5
用户名 adm
6
...

变量

选项中我们可以自定义变量,而这里所需要了解的是内建变量:

  • FS:输入的字段间分隔符
  • OFS:输出的字段间分隔符
  • RS:输入时的换行符
  • ORS:输出时的换行符
  • NF:字段的数量
  • NR:行数
  • FNR:各文件分别计行数
  • FILENAME:当前参数的个数
  • ARGC:命令行参数的个数
  • ARGV:数组,保存的是命令行给定的各参数

示例:

输出当前系统的用户名:

1
~]#awk -v FS=':' -v user='用户名' '{print user,$1}' /etc/passwd

输出当前系统的用户名,并以冒号隔开:

1
~]#awk -v FS=':' -v user='用户名' '{print "user:"$1}' /etc/passwd 
2
3
~]#awk -v FS=':' -v user='用户名' 'BEGIN{OFS=":"}{print user,$1}' /etc/passwd

修改输入换行符

1
[root@localhost ~]#awk -v FS=':' -v user='用户名' 'BEGIN{RS= " "}{print user,$1}' /etc/passwd

修改输出的换行符

1
~]#awk -v FS=':' -v user='用户名' 'BEGIN{ORS=" ";OFS=":"}{print user,$1}' /etc/passwd                       
2
用户名:root 用户名:bin 用户名:daemon 用户名:adm 用户名:lp ...

输出字段数

1
~]#awk -F":" '{print NF}' /etc/passwd
2
7
3
7
4
...         输出的为每行以:隔开共有的字段数
5
6
~]#awk -F":" '{print $NF}' /etc/passwd 
7
/bin/bash
8
/sbin/nologin
9
/sbin/nologin
10
/sbin/nologin
11
/sbin/nologin
12
/bin/sync
13
...            输出最后字段的内容

行数统计

1
~]#awk '{print NR}' /etc/fstab /etc/issue
2
1
3
2
4
3
5
4
6
5
7
6
8
7
9
8
10
9
11
10
12
11
13
12
14
13
15
14
16
15
17
[~]#awk '{print FNR}' /etc/fstab /etc/issue
18
1
19
2
20
3
21
4
22
5
23
6
24
7
25
8
26
9
27
10
28
11
29
12
30
1
31
2
32
3              可以很清楚的看出NR和FNR的差别

参数的查看

1
~]#awk 'END{print ARGC}' /etc/fstab        
2
2
3
4
 ~]#awk 'END{print ARGV[1]}' /etc/fstab 
5
/etc/fstab
6
7
~]#awk 'END{print ARGV[0]}' /etc/fstab 
8
awk

格式化输出

printf format,item1,item2…

  • format必须给出
  • 不会自动换行
  • format中需要分别为后面的每个item制定一个占位符

格式化符号

  • %c:显示字符串的ascii码
  • %d,%i:显示十进制整数
  • %e,%E:科学计数法数值显示
  • %f,显示为浮点型
  • %g,%G:以科学计数法或浮点型形式显示数值
  • %s:显示字符串
  • %u:无字符串
  • %%:显示%本身

修饰符

  • #[.#]:第一个数字控制显示的宽度,第二个#表示小数点后的精度: %3.1f
  • —:减号,左对齐
  • +:显示数值的符号

示例:

1
[root@localhost ~]#awk -F: '{printf "%s\n",$1}' /etc/passwd 
2
root
3
bin
4
daemon
5
adm
6
...
1
~]#awk -F: '{printf "%20s %-d\n",$1,$3}' /etc/passwd 
2
               root 0    
3
                bin 1    
4
             daemon 2    
5
                adm 3    
6
                 lp 4    
7
               sync 5    
8
           shutdown 6    
9
           ...

操作符

算数操作符:

x+y,x-y,x*y,x/y,x^y,x%y

-x +x:转换为数值

字符串操作符:没有符号的操作符,字符操作符

赋值操作符:

=,+=,-=,*=,/=,%=,^=

++,–

比较操作符:

,>=,<,<=,!=,==
模式匹配符:

~:是否匹配 !~:是否不匹配

逻辑操作符 && || !

条件表达式

selector?if-true-expression:if-false-expression

eg:

1
awk -F: '{$3>=1000?usertype="common user":usertype="system admin";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
2
awk -F: '{printf "%15s:%-s",$1,($3>1000?"common user":"system user")}' /etc/passwd

pattern

  • (1)empty 空模式,匹配每一行
  • (2)/regular expression/:仅处理能够被此处的模式匹配到的行
  • (3)relational expression:关系表达式,结果有“真”有“假”,结果为真才会处理

eg:

1
awk -F':' '$NF=="/bin/bash" {print $1,$NF}' /etc/passwd
2
awk -F':' '$NF~/bash$/ {print $1,$NF}' /etc/passwd

line range:行范围

/pat1/,/pat2/

1
awk -F':' '/^root/,/^lp/{print $1}' /etc/passwd

注意;不支持直接给出数字的格式

如果需要处理行数据可以使用下面的方法:

1
~]# awk -F : '(NR>=2&&NR<=10){print $1}' /etc/passwd

BEGIN/END模式

BEGIN{}:仅在开始处理文件中文本之前执行一次

END{}:仅在文本处理完成之后执行一次

控制语句

  • if(condition){statment}
  • if(condition){statment} else {statement}
  • while(condition){statement}
  • do{statement} while(codition)
  • for(exp1,exp2,exp3){statement}
  • break
  • continue
  • delete arry[index]
  • delete arry
  • exit
  • {statement}

if-else

语法:if(condition) statement [else statement]

1
awk -F: '{if($3>1000) print $1,$3}' /etc/passwd
2
awk -F: '{if($3>=1000) {printf "common user: %s\n",$1} else {printf "root or system:%s\n",$1} }' /etc/passwd

使用场景:对awk取得的整行或某个字段做条件判断;

while循环

语法:while(condition) statement

使用场景:对一行内的多个字段逐一类似处理时使用,对数组中逐一处理时使用

1
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /boot/grub2/grub.cfg
2
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>7){print $i,length($i)}; i++}}' /boot/grub2/grub.cfg

do-wile循环

语法:do statement while(condition)

1
awk -F: '{i=1;do{print $i;i++}while(i<=3)}' /etc/passwd

意义;至少执行一次循环

for循环

语法:for(epr1;epr2;epr3) statement

1
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /boot/grub2/grub.cfg
2
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {if(length($i) > 7){print $i,length($i)}}}' /boot/grub2/grub.cfg

特殊用法:

能够遍历数组中的元素:

语法: for(var in arry) (for-body)

switch语句

语法:switch(expression){case VALUE or /REGEXP/:statement;case VALUE2 or /REGEXP2/: statement;…;default:statement}

break和continue

break [n] continue

next

提前结束对本行的处理而直接进入下一行

1
awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd

awk 数组
关联数组:array[index-expression]

index-expression:

(1)可使用任意字符串,字符串要加双引号
(2)如果某组元素事先不存在,在引用时,awk会自动创建此元素,并将某值初始化为“空串”:
若要判断数组中是否存在某元素,要使用“index in array”格式进行

若要遍历数组中的每个元素,要使用for循环

1
awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";for(i in weekdays) {print weekdays[i]}}'

注意:var会遍历array的每个索引

1
netstat -nta | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
2
netstat -ant | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count) {print i,count[i]}}' | sort -k 2 -t " " -nr

统计指定文件中每个单词出现的次数

1
awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab

函数

内置函数:rand();返回0和1之间的一个随机数
字符串处理:
length(s):返回指定字符串的长度
sub(r,s,[t]): 以r表示的模式来查找t所表示的字符串匹配的内容,并将其第一次出现替换为s所表示的内容
gsub(r,s,[t]):以r表示的模式来查找t所表示的字符串匹配的内容,并将其所有出现替换为s所表示的内容
split(s,a[,r]): 已r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中:

1
netstat -ntl | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count) {print i,count[i]}}'

system(command):执行系统command并将结果返回至awk命令

1
 ~]#awk '{print system(ifconfig)}'
2
3
0
4
只返回执行结果

systime():取系统当前时间

1
~]#awk '{print systime()}'
2
3
1488510637

tolower(s):将s中的所有字母转为小写

1
~]#awk -v s='SDADSD' '{print tolower(s)}'
2
3
sdadsd

toupper(s):将s中的所有字母转为大写

1
~]#awk -v s='sssss' '{print toupper(s)}'
2
3
SSSSS
CATALOG
  1. 1. AWK
    1. 1.1. 选项
    2. 1.2. 变量
    3. 1.3. 格式化输出
    4. 1.4. 操作符
    5. 1.5. 条件表达式
    6. 1.6. pattern
      1. 1.6.1. line range:行范围
    7. 1.7. BEGIN/END模式
    8. 1.8. 控制语句
      1. 1.8.1. if-else
      2. 1.8.2. while循环
      3. 1.8.3. do-wile循环
      4. 1.8.4. for循环
      5. 1.8.5. switch语句
      6. 1.8.6. break和continue
      7. 1.8.7. next
      8. 1.8.8. index-expression:
    9. 1.9. 函数