linux三剑客-------AWK

AWK是一种优良的文本处理工具,可以格式化文本输出,同时它本身也拥有自己的语言。AWK 提供了极其强大的功能:可以进行样式装入、 流控制、数学 运算符、进程 控制语句甚至于内置的 变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。接下来,我们一起来认识一下这个强大的语言吧!

一、awk基本介绍

  • 基本格式:awk [options] 'program' file…

[root@blwsy ~]#awk –F:  '{print}'  /etc/passwd

* program通常是被放在单引号或双括号中

* pattern和action:pattern部分决定动作语句何时触发及触发事件 BEGIN,END ;action statements对数据进行处理,放在{}内指明 print, printf

  • 分割符、域和记录

* awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称为域标识 。$0为所有域,注意:和shell中变量$符含义不同

* 文件的每一行称为记录

* 省略action,则默认执行 print $0 的操作

  • 基本用法

awk     [options]  'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file …

[root@blwsy ~]#awk –F:   '{print $1,$3,$7}’ /etc/passwd

* option

-F 指明输入时用到的字段分隔符,不指定分割符是默认空格。

-v var=value: 自定义变量

awk -v FS=':'  ==  awk  -F:

* action

print格式:  print item1, item2, ...

逗号分隔符

各item形式不限,可以字符串,也可以数值,字段或者变量以及awk表达式

如省略item,相当于print $0 ;$0相当于打印文档自身

二、awk变量

*   内置变量
FS:输入字段分隔符

[root@blwsy ~]#awk -v FS=':' '{print $1,$3}' test.txt
apache            48
saslauth          498
postfix             89
gdm                 42
pulse               497
sshd                 74
tcpdump         72
francis            500
setroubleshoot 496
wsy                 501

OFS:输出字段分隔符

[root@blwsy ~]#awk -v FS=':' -v OFS=':' '{print $1,$3}' test.txt
apache:48
saslauth:498
postfix:89
gdm:42
pulse:497
sshd:74
tcpdump:72
francis:500
setroubleshoot:496
wsy:501

RS:输入的记录分隔符
[root@blwsy ~]#awk -v FS="." -v RS=" " '{print $1}' f1(一个文件)
a
bbb
dswwesdds
e3dew4cfv

ORS:输出的记录分隔符
[root@blwsy ~]#awk -v FS="." -v RS=" " -v ORS="#" '{print $1}' f1

a bbb dswwesdds#2133#dasfe#wd699#

NF:字段的数量

[root@blwsy ~]#awk '{print NF}' /etc/fstab
0
6
6
6
6

NR:记录号
[root@blwsy ~]#awk '{print NR,$0}' /etc/fstab

1
2 UUID=929873ac-4dca-40d2-9eeb-a755dbe56096 /boot     ext4   defaults    0  1
3 UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c   /  ext4    defaults  0  2
4 UUID=4acb218c-f541-44aa-a3e0-d491f336a609 /app       ext4  defaults 0   0
5 UUID=646ae8f4-0f05-4feb-aa7d-0fd8906fc8ce swap   swap    defaults   0   0

FNR:各文件分别计数,行号
[root@blwsy ~]#awk '{print FNR}' /etc/fstab /etc/inittab   两个文件分别记录行号

1
2
3
4
5
1
2
3
4
5

….

16

FILENAME:当前文件名
[root@blwsy ~]#awk '{print FILENAME}’ /etc/fstab

[root@blwsy ~]#awk '{print FILENAME}' /etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab

ARGC:命令行参数的个数
[root@blwsy ~]#awk '{print ARGC}'   /etc/fstab /etc/shadow  (参数个数为三,awk也算)

ARGV:数组,保存的是命令行所给定的各参数
[root@blwsy ~]#awk 'BEGIN {print ARGV[2]}'  /etc/fstab  /etc/inittab

/etc/inittab

打印命令行的最后一个参数

[root@blwsy ~]#awk 'BEGIN {print ARGV[ARGC-1]}'  /etc/fstab /etc/inittab /etc/haha hi hello
hello

自定义变量

(1) -v var=value

(2) 在program中直接定义

[root@blwsy ~]#awk -v test="hello awk" '{print test}' /etc/fstab

hello awk
hello awk
hello awk
hello awk
hello awk

[root@blwsy ~]#awk '{sex="male";print sex}' /etc/fstab

male
male
male
male
male

[root@blwsy ~]#awk '{sex="male";print sex,age;age=20}'

male
male 20
male 20
male 20
male 20

  • printf命令(格式化输出)

* 格式化输出:printf “FORMAT”, item1, item2, ...

(1) 必须指定FORMAT

(2) 不会自动换行,需要显式给出换行控制符,\n

(3) FORMAT中需要分别为后面每个item指定格式符

* 格式符:与item一一对应

%c: 显示字符的ASCII码

%d, %i: 显示十进制整数

[root@blwsy ~]#awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd

%e, %E:显示科学计数法数值

%f:显示为浮点数

[root@blwsy ~]#awk 'BEGIN{printf "%.2f\n",1.5*4}'
6.00

%g, %G:以科学计数法或浮点形式显示数值

%s:显示字符串

[root@blwsy ~]# awk -F: 'printf "%s",$1}’'etc/passwd

%u:无符号整数

[root@blwsy ~]#awk 'BEGIN{printf "%u\n",1.5*4}'
6

%%: 显示%自身

[root@blwsy ~]#awk 'BEGIN{printf "%s%\n",1.5*4}'
6%

*  修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

-: 左对齐(默认右对齐) %-15s

+:显示数值的正负符号 %+d

[root@blwsy ~]#df  |awk -v FS=% '$0 ~ "/dev/sd" {print $1}' |awk '$NF>=10 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'
DevName:/dev/sda2  Used:68%
DevName:/dev/sda1  Used:38%

  • 操作符

*模式匹配符:~:左边是否和右边匹配包含!~:是否不匹配

[root@blwsy ~]#awk '$0 ~ "^root" {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

*逻辑操作符:与&&,或||,非!

[root@blwsy ~]# awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
root
nfsnobody

*三目表达式 

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

[root@blwsy ~]#awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin ";printf "%15s:%s\n",$1,usertype}' /etc/passwd

*关系表达式
为非0时,即为真,才处理
为0或为空时,不处理

[root@blwsy ~]# awk -F:  'i=1;j=1{print i,j}' /etc/passwd (i=1时没有指定动作默认输$0,j=1时输出i ,j)

*行范围

[root@blwsy ~]#awk -F: ‘(NR>=10&&NR<=20){print NR,$1}' /etc/passwd

BEGIN/END模式

[root@blwsy ~]#awk -F: 'BEGIN{print " USER UID  \n--------------- "}{print $1,$3}END{print "=============="}' test.txt
  USER UID 
---------------
apache 48
saslauth 498
postfix 89
gdm 42
pulse 497
sshd 74
tcpdump 72
francis 500
setroubleshoot 496
wsy 501
==============

  • awk控制语句

*  if-else   对awk取得的整行或某个字段做条件判断

语法:if(condition){statement;…}[else statement]

             if(condition1){statement1}else if(condition2){statement2} else{statement3}

[root@blwsy ~]#echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"奇数"}else {print $n,"偶数"};n++}}'
1 偶数
2 奇数
3 偶数
4 奇数
5 偶数
6 奇数
7 偶数
8 奇数
9 偶数
10 奇数

 *  while循环   对一行内的多个字段逐一类似处理时使用 对数组中的各元素逐一处理时使用

语法:while(condition){statement;…}

条件“真”,进入循环;条件“假”,退出循环

[root@blwsy ~]#cat /boot/grub/grub.conf  |awk '/^[[:space:]]*kernel/{i=1;while(i<=NF){print $i,length($i);i++}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30
ro 2
root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46
rhgb 4
crashkernel=auto 16
LANG=zh_CN.UTF-8 16
KEYTABLE=us 11

*  do-while循环

语法:do {statement;…}while(condition)

意义:无论真假,至少执行一次循环体

[root@blwsy ~]#awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);{print total}}'
5050

*  for循环

语法:for(expr1;expr2;expr3) {statement;…}

[root@blwsy ~]#cat /boot/grub/grub.conf  |awk '/^[[:space:]]*kernel/{for(i=1;i<=NF;i++){print $i,length($i)}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30
ro 2
root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46
rhgb 4
crashkernel=auto 16
LANG=zh_CN.UTF-8 16
KEYTABLE=us 11

* continue 和break

continue 结束本次循环,继续执行下次循环

break 结束此次循环,后边可加数字表示跳出几层循环

计算1到100 所有偶数之和
[root@blwsy ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'

2550

*next

提前结束对本行处理而直接进入下一行处理(awk自身循环)

[root@blwsy ~]#awk -v FS=: '{if($3%2!=0) next;print $1,$3}' /etc/passwd

  • awk数组

关联数组:array[index-expression]

* index-expression:

   (1) 可使用任意字符串;字符串要使用双引号括起来

   (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

* 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

计算etc/passwd中,shell脚本的类型及个数

[root@localhost ~]# awk -F: '{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd
/sbin/shutdown 1
/bin/bash 1
/sbin/nologin 29
/sbin/halt 1
/bin/sync 1

  • 函数

*数值处理:

          rand():返回0和1之间一个随机数

[root@localhost ~]# awk 'BEGIN{srand();print int(rand()*100) }'     srand()函数要和rand()函数一起使用
84                             

*字符串处理:

length([s]):返回指定字符串的长度

[root@localhost ~]# awk 'BEGIN{print length("hello")}'
5

• sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)'

2008-08:08 08:08:08

• gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)'

2008-08-08 08-08-08

• split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组 中,第一个索引值为1,第二个索引值为2,…

[root@localhost ~]# netstat -tan |awk '/^tcp\>/ && !($5 ~ "*"){split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
172.18.250.203 2

  • 自定义函数

 格式: function name ( parameter, parameter,  ... ) { statements return expression }

  自定义一个比较大小的awk函数

[root@localhost ~]#vim fun.awk

function max(a,b){
if (a>b)
  var=a
else
  var=b
return var
}
BEGIN{a=5;b=8;print max(a,b)}

[root@localhost ~]# awk -f fun.awk
8

*awk中调用shell命令

用 system命令进行函数调用

空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律用""引用起来。

[root@localhost ~]#awk BEGIN'{system("hostname") }'

localhost.localdomain

[root@localhost ~]#awk 'BEGIN{score=100; system("echo  your score is " score) }'

your score is 100

*awk脚本

将awk程序写成脚本,直接调用或执行

[root@localhost ~]# cat fun.awk
#!/bin/awk -f
BEGIN{FS=":"}
{if($3>=1000)print $1,$3}

[root@localhost ~]#chmod +x fun.awk

[root@localhost ~]#./fun.awk  /etc/passwd

nfsnobody 65534


实例

1、统计/etc/fstab文件中每个文件系统类型出现的次数
[root@localhost ~]# cat /etc/fstab |awk '!($0 ~ "#"){print $0}'|awk '{line[$3]++}END{for(i in line){print i,line[i]}}'
  3
devpts 1
swap 1
sysfs 1
proc 1
tmpfs 1
ext4 3

2、统计/etc/fstab文件中每个单词出现的次数
[root@localhost ~]# awk '{for(i=1;i<=NF;i=i+1){print $i}}' /etc/fstab |sort|uniq -c|sort -nr|awk '{printf("%s %s\n",$2,$1)}'

3、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字
[root@localhost ~]# echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub(/[^[:digit:]]/," ")'
     05   9    7        3











猜你喜欢

转载自www.cnblogs.com/w-s-y/p/9559334.html