15awk命令

linux三剑客之awk

1、什么是awk,主要作用是什么

主要是用来处理文本的,将文本按照指定的格式输出。其中包含变量,循环以及数组

2、awk的格式

awk [选项] '匹配规则和处理规则' [处理文本路径]
awk -F: '{print $1}' /etc/passwd

标准输出 | awk [选项] '匹配规则和处理规则'
cat /etc/passwd | awk -F: '{print $1}'

匹配规则主要是正则表达式
处理规则:
设置变量
设置数组
定义函数
数组循环
加减乘除运算
字符串拼接

匹配规则:
1、字符串
2、正则表达式
处理规则:
BEGIN{} : BEGIN是在awk处理文本之前运行
~ : 表示模式开始
// : 使用的匹配规则
{} : 循环(处理每一行时要执行的语句)
END{} : 当所有的处理全部执行完毕之后,执行END中相关操作
   
案例1、把/etc/passwd中的包含root的行打印出来
awk -F: '/root/' /etc/passwd

案例2、输出/etc/passwd中第一列包含"root",并打印第一列和第三列
awk -F: '$1 ~ /root/ {print $1,$3}' /etc/passwd

案例3、把/etc/passwd中的以root开头的行打印出来
awk -F: '/^root/' /etc/passwd

案例4、将/etc/passwd中匹配的第三列和第五列的数据
awd -F: '{print $3,$5}' /etc/passwd

案例5、打印以root或者ntp开头的行的解析器
awk -F: '/^(root|ntp)/{print $7}' /etc/passwd

3、awk的工作原理

(1)awk会接收一行作为输入,并将这一行赋给awk的内部变量$0,每一行也可以称为一个记录,行的边界是以换行符作为结束(表明:awk是一行一行地去处理文本的)

(2)然后刚刚读入的行被以 : 分隔符分解成若干字段(或域),每个字段存储在已编号的变量中,编号从$1开始,最多达100个字段

注意:如果未指定行分隔符,awk将使用内置变量FS的值作为默认的行分隔符,FS默认值为空格,如果说要指定分隔符,需要使用-F参数或者重新定义FS变量

(3)使用print函数打印,如果$1 $3之间没有逗号,他俩在输出时将贴在一起,应该在$1 $3之间加逗号,该逗号与awk的内置变量OFS保持一致,OFS默认为空格,于是以空格为分隔符输出$1,$3
我们可以指定:awk -F: 'BEGIN{OFS="-"}{print $1,$3}' /etc/passwd

(4)输出之后,将从文件中获取另一行,然后覆盖给$0,继续(2)的步骤将该行内容分割成字段。继续(3)的步骤,直至持续到所有行处理完毕

4、awk中的变量

$0  :保存当前行的内容
$n :当前记录的第n个字段,字段间由FS分割
NR :记录号(行号),每处理完一条记录,NR值加1
FNR :各文件分别计数的行号
NF :保存记录的字段数, $1,$2,...,$100
RS :记录分隔符,默认值是一个换行符
FS :输入字段分隔符,默认空格(相当于-F)
-F可以指定一个或多个
一个: -F: -F, 等
多个: -F'[ ,]' -F'[\,]'   等
OFS :输出字段分隔符,默认值与输入字段分隔符一致
ORS :输出记录分隔符,默认值是一个换行符

案例1:输出/etc/passwd中的所有内容包括行号
awk '{print NR,$0}' /etc/passwd

案例2、要求把第7行之后的内容输出出来,包括行号
awk 'NR > 7{print NR,$0}' /etc/passwd
awk '{if(NR>7){print NR,$1}}' /etc/passwd

案例3、要求输出第7行之后至第14行之前的内容,包括行号
awk 'NR > 7 && NR < 14{print NR,$0}' /etc/passwd
awk '{if(NR > 7 && NR < 14){print NR,$0}}' /etc/passwd

案例4、由案例3,要求输出每行的UID增加1
awk -F: 'NR > 7 && NR < 14{print $3,$3+1}' /etc/passd
awk -F: '{if(NR > 7 && NR < 14){print $3,$3+1}}' /etc/passd

案例5、要求输出倒数第3列
awk -F: '{print $(NF-2)}' /etc/passwd

案例6、要求不使用-F参数,以:分割并输出第3列和第5列
awk 'BEGIN{FS=":"}{print $3,$5}' /etc/passwd
   
案例7、要求实验证明-F 和 FS的优先级
awk -F/ 'BEGIN{FS=":"}{print $7,$3}' /etc/passwd
证明得出-F参数的优先级小于FS变量的优先级

案例8、要求以:分割,并输出第3列和第5列,第3列和第5列之间使用+号分割
awk -F: 'BEGIN{OFS="+"}{print $3,$5}' /etc/passwd
awk 'BEGIN{FS=":";OFS="+"}{ptint $3,$5}' /etc/passwd
注:所有的变量的定义都应该放在BEGIN里面

案例9、计算/etc/passwd的大小
ll /etc/passwd | awk '{sum+=$5} END{print sum}'

5、格式化输出

%s  字符类型
%d 数值类型
占15格的字符串
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n

print和printf的区别:
print在显示多个结果的时候以逗号分隔,结果将这几部分的内容自动使用分隔进行分隔,且不需要添加换行符
printf可以更加灵活的控制某一个字段的输出格式,通过使用诸如%-12s,%3.1f等格式化方法


案例1、要求输出第1列和最后1列,排版整齐
awk -F: '{printf "%-16s %s \n",$1,$NF}' /etc/passwd

6、操作模式

1、正则模式
awk -F: '/^xxx/' /etc/passwd

2、比较模式
> <
awk -F 'NR > 7' /etc/passwd

3、条件模式
awk -F 'NR > 7' /etc/passwd

4、算数运算
awk -F '{print $3,$3+1}' /etc/passwd

5、范围模式
awk -F: '/root/,/ftp/{print $1}' /etc/passwd

7、流程控制

if判断
  单分支
  if(){}
  双分支
if(){} else{}
多分支
if(){} else if() {} else{}

案例1、打印奇数行的数据
awk '{if(NR % 2){print NR, $0}}' /etc/passwd

案例2、打印偶数行的数据
awk '{if(NR % 2 == 0){print NR, $0}}' /etc/passwd
awk '{if(!(NR%2)){print NR,$0}}' /etc/passwd
awk 'NR%2==0{print $0}' /etc/passwd

注:单分支情况下是可以省略if,多分支情况下不能省略

案例3、要求打印出偶数行中包含bash的行
awk -F: '/bash/{if(NR % 2 == 0){print NR, $0}}' /etc/passwd

案例4、要求在奇数行前输出奇数,偶数行前输出偶数
awk -F: '{if(NR % 2){printf "奇数行:%s\n", $0} else{printf "偶数行:%s\n", $0}}' /etc/passwd

案例5、在前7行前加7,在前14行前加14,其他原样输出
awk -F: '{if(NR<=7){printf "7 %s \n", $0} else if(NR<=14){printf "14 %s \n", $0} else {print $0}}' /etc/passwd


for
for(变量 in 数组){语句}
for(变量;条件;表达式){语句}
知识储备:
++ : 每次加1
-- : 每次减1

案例1、将/etc/nginx/nginx.conf中的所有的词的个数
egrep -o "[a-zA-Z0-9]+" /etc/nginx/nginx.conf | awk '{arr[$1]++}END{for(i in arr){printf "%-20s %d\n",i,arr[i]}}'

案例2、要求统计以#开头的行中包含的词的个数
egrep '^ *#' /etc/fstab | egrep -o "[a-zA-Z0-9]+" | awk '{arr[$1]++}END{for(i in arr){printf "%-20s %d\n",i,arr[i]}}'

案例3、输入一个文件路径,要求打印出它的数字权限(不允许使用stat)
ll [路径] | awk 'BEGIN{FS=""}{if($2=="r"){u=u+4} if($3=="w"){u=u+2} if($4=="x"){u=u+1} if($5=="r"){g=g+4} if($6=="w"){g=g+2} if($7=="x"){g=g+1} if($8=="r"){o=o+4} if($9=="w"){o=o+2} if($10=="x"){o=o+1}}END{print u,g,o}'
}'


while

awk脚本

BEGIN块:awk在开始处理输入文件之前会执行BEGIN块,其是初始化FS(字段分隔符)变量、打印页眉或者初始化其他在程序中以后会引用的全局变量的极佳位置

END块:awk在处理了输入文件中的所有行之后执行这个块,其用于执行最终计算或者打印应该出现在输出结尾的摘要信息。

假设有这么一个文件(学生成绩表)

cat score.txt

Marry   2143   78   84   77
Jack     2321   66   77   45
Tom     2122   48   77   71
Mike     2537   87   97   95
Bob     2415   40   57   62

我们的awk脚本如下:

cat cal.awk
#!/bin/awk -f
#运行前
BEGIN{
math = 0
english = 0
computer = 0

print "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
print "---------------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
print "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3, $4, $5, $3+$4+$5
}
#运行后
END{
print "---------------------------------------------------\n"
ptint "TOTAL:%10d %8d %8d \n", math, english, computer
print "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

字符串函数的应用

1、替换	gsub
将 this is a test2010test! 中的数字替换成 !
awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'

2、查找 index
查找 this is a test2010test! 中的 test
awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'

3、匹配查找 match
awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'

4、截取 substr
截取字符串中第四个到第十个字符
awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'

5、分割 split
awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'

 

 

上一篇:【CF1349D】Slime and Biscuits(势能函数)


下一篇:grep、sed 和 awk 文本三剑客