AWK是一种编程语言,用于在Linux、unix下对文本和数据进行扫描与处理,数据可以来自标准输入、文件、管道。
逐行扫描文件,从第一行到最后一行,寻找匹配特定模式的行,并在这些行上进行用户想要的操作
pattern {action}
没有指定模式匹配,则默认匹配所有数据,默认处理动作是print打印行
Awk模式:
BEGIN模式:
在读取文件内容之前,BEGIN后面的指令将执行,然而读取文件内容并判断是否与特定模式匹配,如果匹配,则执行后面的动作指令
END模式:
在读取文件内容之后,END后面的指令将被执行
Awk基本语法格式:
awk [参数] -f program-file [--] file ......
模式可以是BEGIN、END、表达式,用来限定操作对象的多个表达式使用逗号分隔;动作指令需要{}引起来。
-F fs 指定以fs作为输入行的分隔符(默认分隔符为空格或制表符)
-v var=val 在执行处理过程以前,这是一个变量var值为val
-f file 从脚本文件中读取Awk指令,以取代在命令参数中输入处理脚本
列子:
awk ‘/^$/ {print "Blank line"} ’ test.txt #
awk '/HOSTNAME/' /etc/sysconfig/network
Awk操作指令:
记录与字段
Awk一次从文件中读取一条记录,并将记录存储在字段变量$0中。记录被分割为字段并存储在$1,$2,......$NF中(默认使用空格或制表符为分隔符)。内建变量NF为记录的字段个数。
echo "hello the world" | awk '{print $1,$2,$3}' #读取输入行并输出第一个字段、第二个字段、第三个字段
echo “hello the world" | awk '{print $0 }' #读取输入行并输出该行
echo "hello the world" | awk '{print NF}' #读取输入行并输出该行的字段个数
echo "hello the world" | awk '{print $NF}' #读取输入行并输出该行的最后一个字段
字段与分隔符
默认Awk以空格或制表符作为分隔符,但可以通过-F或FS变量来改变分隔符。
awk -F: ‘{pring $1}’ /etc/passwd
awk 'BEGIN {FS = ":"} {Print $1} ' /etc/passwd
指定多个字段分隔符
echo " hello the:world,! " | awk 'BEGIN {FS = "[:, ]"} {print $1,$2,$3,$4} '
内置变量
ARGC 命令行参数个数
FILENAME 当前输入文档的名称
FNR 当前输入文档的当前记录编号,尤其是当有多个输入文档时有用
NR 输入流的当前编号
NF 当前记录的字段个数
FS 字段分隔符
OFS 输出字段分隔符,默认为空格
ORS 输出记录分隔符,默认为\n
RS 输入记录分隔符,默认为换行符\n
[root@centos6 ~] # cat test1.txt
this is a test file.
Welcome to Jacob's Class.
[root@centos6 ~] # cat test2.txt
Hello the wrold
Wow! I'm overwhelmed
Ask for more
输出当前文档的当前行编号,第一个文件两行,第一个文件三行:
[root@centos6 ~] # awk ' {print FNR} ' test1.txt test2.txt
1
2
1
2
3
Awk将两个文档作为一个整体的输入流,通过NR输入当前行编号:
[root@centos6 ~] # awk ' {print NR} ' test1.txt test2.txt
1
2
3
4
5
[root@centos6 ~] # awk '{print NF}' test1.txt #文档的第一行有5个字段,第二行有4个字段
5
4
[root@centos6 ~] # awk ‘BEGIN {FS = “:” } {print $1} ’ /etc/passwd
下面通过OFS将输出分隔符设置为“-”, 这个print在输出第一、第二、三个字段时,中间的分隔符为“-”,
[root@centos6 ~] # awk 'BEGIN {OFS= "-" } {print $1,$2,$3} ' test1.txt
读取输入数据,以空白行为记录分隔符,即第一个空白行前的内容为第一个记录,第一个记录中字段分隔符为换行符,打印出每个记录的第三个字段
[root@centos6 ~] # cat test3.txt
mail from: tomcat@gmail.com
subject:hello
data:2012-07-12 17:00
content:Hello, the world.
mail from: jerry@gmail.com
subject:congregation
data:2012-07-12 08:31
content:Congregation to you
[root@centos6 ~] # awk 'BEGIN {FS = "\n" ; RS="" } {print $3} ' test3.txt
表达式与操作符
表达式由变量、常量、函数、正则表达式、操作符组成,AWK中定义的变量没有初始化,则初始值为空字串或0.注意,
字符操作时一定记住需要加引号。
变量定义示列:
a="welcome to beijing"
b =12
操作符(awk操作符与C语言类似)如下。
+ 加
- 减
* 乘
/ 除
% 取余
^ 冥运算
++ 自加1
-- 自减1
+= 相加后赋值给变量(x+=9等同于x=x+9)
-= 相减后赋值给变量(x-=9等同于x=x-9)
*= 相乘后赋值给变量(x*=9等同于x=x*9)
/= 相除后赋值给变量(x/=9等同于x=x/9)
> 大于
< 小于
>= 大于或等于
<= 小于或等于
== 等于
!= 不等于
~ 匹配
!~ 不匹配
&& 与
|| 或
[root@centos6 ~] # echo “test” | awk 'x=2 {print x+3} '
[root@centos6 ~] # echo "test" | awk ' x=2,y=3 {print x*2,y*3}'
[root@centos6 ~] # awk '/^$/ {print x+=1}' test.txt #统计 所有的空白行
[root@centos6 ~] # awk ‘/^$/ {x+=1} END {print x}’ test.txt #打印总空白行个数
[root@centos6 ~] # awk -F: '$1~/root/ {print $3}' /etc/passwd #打印root的ID号
[root@centos6 ~] # awk -F: '$3>500 {print $1}' /etc/passwd #列出计算机中ID号大于500的用户名
Awk高级应用
1.IF添加判断
if语法格式1:
if (表达式)
动作1
else
动作2
if语法格式2:
if (表达式) 动作1; else 动作2
示例:boot分区可用容量小于20MB时报警,否则显示OK
df | grep “boot” | awk ‘{if ($4<20000) print "Alart" ; else print "OK" } ’
while 循环
while语法格式1:
while(条件)
动作
语法格式示例如下:
i=1
while (i < 10) {
print $i
}
[root@centos6 ~] awk 'i=1 {} BEGIN { while (i<=10) {++i;print i} } ' test.txt
While语法格式2:
do
动作
While (条件)
[root@centos6 ~]awk ' BEGIN { do {++i ; print i } while ( i<=10) } ' test.txt
3.for循环
for (变量;条件;计数器)
动作
示例:
[root@centos6 ~] awk 'BEGIN { for (i=1;i<=10;i++) print i } ' test.txt
以上循环语句使用的awk均使用BEGIN模式,也就是说,在未读取文档内容前就会BEGIN代码执行完毕,所以输入文档可以为任意文档
Break与Continue
break跳出循环
continue 终止当前循环
示例:
for (i=1;i<=10;i++) { #打印1-4,6-10
if (i=5)
continue
print i
}
for (i=1;i<=10;i++) { #只打印1-4
if (i=5)
break
print i
}
函数
(1 ) rand()函数
作用:产生0~1之间的浮点类型的随机数,rand产生随机数时需要通过srand()设置一个参数,否则单独的rand()每次产生的随机数都是一样的。
[root@centos6 ~] # awk 'BEGIN {print rand() ; srand(); print srand() } ' test.txt
(2)gsub(x,y,z)函数
作用:在字串z中使用字串y替换与正则表达式x相匹配的所有字串,z默认为$0.
(3)sub(x,y,z)函数
作用:在字串z中使用字串y替换与正则表达式x相匹配的第一个字串,z默认为$0.
将passwd每行中所有的root修改为jacob显示至屏幕:
[root@centos6 ~]awk -F: 'gsub(/root/ ,"jacob",$0) {print $0} ' /etc/passwd
将passwd每行中第一个root修改为jacob显示至屏幕:
[root@centos6 ~] awk -F: 'sub(/root/,"jacob",$0) {print $0} ' /etc/passwd
sub相当于sed中s///,gsub相当于sed中的s///g
(4)length(z)函数
作用:计算并返回字串z的长度
显示test.txt文档每行的字符长度:
[root@centos6 ~] # awk '{print lenth()}' test.txt
(5)getline函数
作用:从输入中读取下一行内容。从下面df -h命令的输出结果可以看出,分区的剩余容量显示在第四列,
但唯独/根分区的记录显示在了两行。我们需要判断当记录的字段个数为1小时,读取下一行,并将该行的第3列显示至屏幕
[root@centos6 ~] # df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
19G 3.6G 15G 21% /
/dev/sda1 99M 14M 81M 15% /boot
tmpfs 141M 0 141M 0% /dev/shm
none 140M 104K 140M 1% /var/lib/xenstored
[root@centos6 ~] df -h | awk ' {if (NF==1)} {getline ; print $3} ; if (NF==6) print $4 '
[root@centos6 ~] df -h | awk ' BEGIN {PRINT "Disk Free:"} > { if (NF==1) {getline; print $3 }; if(NF==6) print $4 } '