day15 linux三剑客之awk

 

 

 

1.awk

1.什么是awk,主要作用是什么?
awk主要擅长处理有规律的文本,主要用于做一些格式化处理,将文本按照指定的格式输出。其中包含变量,循环以及数组。

2.awk的格式:
格式1:
   awk 选项 '规则' 文件路径
  [root@localhost ~]# awk -F: '{print $1}' /etc/passwd
格式2:
  标准输出 | awk [选项] '匹配规则和处理规则'
  [root@localhost ~]# cat /etc/passwd |awk -F: '{print $1}'

选项:-F 指定分隔符
规则:定位+命令
定位:
    行号定位:NR==1
    正则定位:awk -F: '//{print $1 $2}' 文件路径
      没有定位表示定位所有行
  命令:{print $n}
匹配规则主要是正则表达式
处理规则就有很多了:
设置变量
设置数组
数组循环
加减乘数运算
字符串拼接
匹配规则:1.字符串
        2.正则表达式
处理规则:BEGIN{}   :BEGIN是在awk处理文本之前运行
        //         :使用的匹配规则
        /正则/       # 该行内容匹配成功正则
        $1 ~ /正则/  # 第一段内容匹配成功正则
       $1 !~ /正则/  # 第一段内容没有匹配成功正则
        {}         :循环(每次只处理一行数据)
        END{}     :当所有的处理全部执行完毕之后,执行END中的相关操作
       
  案例1:打印第三行的第一列和第三列
   awk -F: 'NR==3{print $1,$3}' /etc/passwd
  案例2打印第三行到第五行的第一列和第三列
   awk -F: 'NR>=3 && NR<=5 {print $1,$3}' /etc/passwd
  案例3:打印前三行或者大于第8行的第一列和第三列
   awk -F: 'NR<=3 || NR>=8 {print $1,$3}' /etc/passwd
  案例4:打印所有的nologin结尾的第一列
   awk -F: '/nologin$/ {print $1}' /etc/passwd
  案例5:打印/etc/passwd的最后一列
   awk -F: '{print $NF}' /etc/passwd
  案例6:把/etc/passwd中的包含root的行打印出来
  [root@localhost ~]# awk -F: '/root/' /etc/passwd
  root:x:0:0:root:/root:/bin/bash
  operator:x:11:0:operator:/root:/sbin/nologin
  案例7:把/etc/passwd中以root开头的行打印出来
  [root@localhost ~]# awk -F: '/^root/' /etc/passwd
  root:x:0:0:root:/root:/bin/bash
  案例8:将/etc/passwd中匹配第三列和第五列的数据
  [root@localhost ~]# awk -F: '{print $3,$5}' /etc/passwd
  案例9:打印以root或者ntp开头的行的解析器
  [root@localhost ~]# awk -F: '/^root|^ntp/{print $7}' /etc/passwd
[root@localhost ~]# awk -F: '/^(root|ntp)/{print $7}' /etc/passwd
   

2.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)的步骤,该过程一直持续到所有行处理完毕

简洁版:
1、awk会读取文件的一行内容然后赋值给$0
2、然后awk会以-F指定的分隔符将该行切分成n段,最多可以达到100段,第一段给$1,第二段给$2,依次次类推
3、print输出该行的第一段和第三段,逗号代表输出分隔符,默认与-F保持一致
4、重复步骤1,2,3直到文件内容读完

3.awk中的变量

$0:一整行内容
NR:记录号(行号),每处理完一条记录,NR值加1
NF:以-F分隔符分隔的段数,$1,$2...$100
FS:输入字段分割符,默认空格
OFS:输出字段分隔符

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

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

案例3:要求输出第7行之后的内容且第14行之前的内容输出出来,包含行号
awk -F: 'NR>7 && NR<14{print NR,$0}' /etc/passwd

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

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

案例6:要求不使用-F参数,以:分割,并输出第3列和第5列
awk 'BEGIN{FS=":"}{print $5,$3}' /etc/passwd

案例7:要求实验证明-F 和 FS的优先级
awk -F/ 'BEGIN{FS=":"}{print $7,$3}' /etc/passwd
证明得出-F参数的优先级小于FS变量的优先级

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

4.格式化输出

================print函数===================
date | awk '{print "月:",$2,"\n年:",$1}'
月: 09月
年: 2020年

awk -F: '{print "用户名:",$1,"用户id:",$3}' /etc/passwd

================printf函数===================
awk -F: '{printf "用户名:%s 用户id:%s\n",$1,$3}' /etc/passwd
awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd

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

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

5.操作模式

1.正则模式  awk -F: '/^root/' /etc/passwd
2.比较模式  awk -F: 'NR > 7{print $0}' /etc/passwd
3.条件模式  awk -F: 'NR > 7{print $0}' /etc/passwd
4.算数运算  awk -F: '{print $3,$3+1}' /etc/passwd
5.范围模式  awk -F: '/root/,/ftp/{print $1}' /etc/passwd

6.流程控制

if判断
    单分支   if () {}
    双分支  if () {} else {}
    多分支  if(){} else if() {} else{}
   
    案例1:打印奇数行的数据
      awk -F: '{if(NR % 2){print NR,$0}}' /etc/passwd
     
    案例2.打印偶数行的数据
      awk -F: '{if(NR % 2==0){print NR,$0}}' /etc/passwd
    或 awk -F: 'NR%2==0{print NR,$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 循环

    

while循环while (判断条件) {}

案例1:把/etc/passwd中的每一行都重复打印3遍

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

案例2:统计/etc/passwd中每个解析器的用户数

awk -F: '{arr[$NF]++}END{for (i in arr){print i,arr[i]}}' /etc/passwd

案例3:要求把/etc/passwd中第10行的中每一列都打印出来
[root@localhost ~]# awk -F: 'NR==10{i=0;while(i<=NF){print $i;i++}}' /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
operator
x
11
0
operator
/root
/sbin/nologin

 

posted @ 2021-10-09 22:55  甜甜de微笑  阅读(90)  评论(0编辑  收藏  举报