shell脚本——awk详细介绍(包含应用案例)

Posted 0611#

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell脚本——awk详细介绍(包含应用案例)相关的知识,希望对你有一定的参考价值。

awk概述

  • awk是一种编程语言,用于在linux/unix下对文本和数据进行处理
  • 数据可以来自标准输入、一个或多个文件,或其他命令的输出。
  • 它支持用户自定义函数动态正则表达式等先进功能。

awk处理文本方式

  • awk的处理文本和数据的方式是这样的,
  • 逐行扫描文件,从第一行到最后一行,
  • 寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
  • 如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕)。
  • awk分别代表其作者姓氏的第一个字母,因为他的作者是三个人,分别是Alfred Aho、Peter Weinberger、Kernighan。

awk工作原理

awk -F:'{print $1,$3}' /etc/passwd
  • awk使用一行作为输入,并在这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束
  • 然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始 最多达100个字段
  • awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理,该过程将持续到所有行处理完毕
  • 一行被称为记录,一个词称为字段

awk语法

awk [选项] '命令' 文件名 (推荐)
  • 选项:例如 -F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
  • 命令(时空):过去 现在 将来
  • BEGIN{}:begin发生在行处理前(注意大写)
  • { } :行处理时,读一次执行一次
  • END{}:=行处理之后

汇总示例

示例文件准备:为了使操作结果看起来简单易懂在每一行最后添加了数字

[root@pakho ~]# head /etc/passwd >passwd
[root@pakho ~]# cat passwd 
root:x:0:0:root:/root:/bin/bash1
bin:x:1:1:bin:/bin:/sbin/nologin2
daemon:x:2:2:daemon:/sbin:/sbin/nologin3
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
halt:x:7:0:halt:/sbin:/sbin/halt8
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin9
operator:x:11:0:operator:/root:/sbin/nologin10

内部变量

一、FS<:输入字段分隔符(默认空格)

[root@pakho ~]# awk 'BEGIN{FS=":"}{print $1}' passwd  #等同于-F:
  • 效果展示

二、OFS:输出字段分隔符

[root@pakho ~]# awk 'BEGIN{FS=":";OFS="++--++"}{print $1,$2,$3}' passwd 

OFS定义输出的字符想怎么写就怎么写

  • 效果展示

三、 RS输入记录(行)分隔符,默认换行符

[root@pakho ~]# awk 'BEGIN{RS=":"}{print $0}' passwd  #会把:当做一条记录

四、ORS 输出记录(行)分隔符,默认换行符

[root@pakho ~]# awk 'BEGIN{ORS="+++"}{print $0}' passwd 
  • 效果展示

五、FNR 多文件独立编号

准备了两个文件

[root@pakho ~]# awk '{print FNR,$0}' 1.txt passwd   #查看了两个文件 但都会显示自己文件的独立编号
  • 效果展示

六、NR多文件汇总编号

[root@pakho ~]# awk '{print NR,$0}' 1.txt passwd  #汇总行号
  • 效果展示

七、★NF字段总数

[root@pakho ~]# awk '{print NF,$0}' 1.txt 
  • 效果展示
[root@pakho ~]# awk '{print $NF}' 1.txt   #NF是6 那么$NF就是$6 

格式化输出

print参数

[root@pakho ~]# awk -F: '{print "账号名:" $1}' passwd | head -1
账号名:root
[root@pakho ~]# awk -F: '{print "账号名:"$1" \\t用户的ID是:"$3}' passwd | head -2
账号名:root 	用户的ID是:0
账号名:bin 	用户的ID是:1                    #-t是回车的意思

模式(正则表达)和动作

概念

  • 任何awk语句都由模式和动作组成,模式部分决定动作语句何时触发及触发事件,
  • 如果省略模式部分,动作将时刻保持执行状态,每一行都会有动作。
  • 模式可以是任何条件语句或复合语句或正则表达式,有模式的话,就是对模式对应的行进行动作。

字符串比较

[root@pakho ~]# awk -F: '/^root/' passwd    
[root@pakho ~]# awk -F: '$0 ~ /^root/' passwd  #这一行记录好像是root开头的  $0表示记录 ~表示好像
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]# awk -F: '$0 !~ /^root/' passwd  #这一行记录不像是root开头的 !取反
bin:x:1:1:bin:/bin:/sbin/nologin2
daemon:x:2:2:daemon:/sbin:/sbin/nologin3
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
halt:x:7:0:halt:/sbin:/sbin/halt8
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin9
operator:x:11:0:operator:/root:/sbin/nologin10

数值比较

目的

  • 比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作,比较表达式使用关系运算符,
  • 用于比较数字与字符串

关系运算符

语法:

  1. < 小于
  2. <= 小于或等于
  3. == 等于
  4. != 不等于
  5. >= 大于等于
  6. > 大于
[root@pakho ~]# awk -F: '$3 > 10' passwd   #查找id号大于10的账号
operator:x:11:0:operator:/root:/sbin/nologin10
[root@pakho ~]# awk -F: '$3 == 0' passwd   #查找id号等于0的账号
root:x:0:0:root:/root:/bin/bash1

算术运算

语法:+ - * / %(模) ^(幂2 ^ 3 )

#示例
[root@pakho ~]# awk -F: '$3 * 5 > 50'  passwd   #文件中只有operator $3 * 5 大于50
operator:x:11:0:operator:/root:/sbin/nologin10

多条件运算

  • 逻辑操作符和复合模式

语法

  • &&逻辑与a&&b
  • | | 逻辑与a | | b
  • !逻辑非!a
#示例
[root@pakho ~]# awk -F: '$1 ~ /ro/&& $3 == 0' passwd    #$1好像是ro 并且$3=0
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]#  awk -F: '$1 ~ /r/&& $3 <= 10' passwd   #拿出10的参数条件与之对比
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]# awk -F: '/adm/,/shutdown/' passwd       #查询adm到shutdown的内容
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7

awk脚本编程

变量

awk调用变量

  • 自定义内部变量 -v 参数 -v:定义变量
[root@pakho ~]# awk -F: -v bianliang=shutdown '$1 == bianliang' passwd   #定义变量bianliang 调用变量biangliang 查询shutdown
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
  • 外部变量 " ' "

注意:awk使用外部变量时,外部使用双引号,内部也使用双引号,但需要转义内部的双引号

[root@pakho ~]# heihei=shutdown                          #首先定义外部变量
[root@pakho ~]# awk -F: '$1 ~ "'"$heihei"'"'   passwd    #调用变量
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7

双重否定等于肯定所以使用三重否定需要加引号二次转义

条件判断

一、单分支 if语句

  • 格式: if语句 格式{if(表达式{语句;语句;…})} if(条件测试){执行语句}
#需求:如果$3是0,就说他是管理员
[root@pakho ~]# awk -F:  '{if($3==0){print $1 "是管理员"}}' passwd 
root是管理员

二、双分支 if…else语句

  • 格式:{if(表达式){语句;语句;…} else{语句;语句;…}} if(条件测试){条件成立执行语句}eles{条件不成立执行语句}
#需求:uid是0就说他是管理员否则就说他是普通用户
[root@pakho ~]# awk -F:  '{if($3==0){print $1 "是管理员"} else {print $1 "是普通用户"}}' passwd  
root是管理员
bin是普通用户
daemon是普通用户
adm是普通用户
lp是普通用户
sync是普通用户
shutdown是普通用户
halt是普通用户
mail是普通用户
operator是普通用户
#需求:统计管理员和系统用户数量
[root@pakho ~]# awk -F: '{if($3==0){i++}else{u++}}END{print i;print u}'  passwd
1
9

三、 多分支 if…else if…else语句

  • 格式:{if(表达式1){语句;语句;…}else if(表达式2){语句;语句;…}else if(表达式3){语句;语句…}}
#需求:统计出三种用户的信息,管理员ID为0 内置用户ID<1000 普通用户ID>999
[root@pakho ~]# awk -F: '{ if($3==0){a++} else if ($3>999){b++} else {c++} }END{print a;print b;print c}' /etc/passwd
1
2
24
[root@pakho ~]# awk -F: '{ if($3==0){a++} else if ($3>999){b++} else {c++} }END{print a "是超管";print b"是普通用户";print c"是内置用户"}' /etc/passwd
[root@pakho ~]# awk -F: '{if($3==0){print $1,"是超管"}else if($3>999){print $1,"是普通用户"}else{print $1,"是程序用户"}}'  /etc/passwd

循环

一、while循环

#循环打印10个数字
[root@pakho ~]# awk 'BEGIN{while(i<=10){print i;i++}}' passwd 
#每一行打印10次
[root@pakho ~]# awk -F: '{while(i<=9){print $0;i++}}' passwd 

二、for循环

#循环打印5个数字
[root@pakho ~]# awk -F: 'BEGIN{for(i=1;i<=5;i++){print i}}' 
#每行打印10次
[root@pakho ~]# awk -F: '{for(i=1;i<=10;i++){print $0}}' passwd 
#打印每一行的每一列
[root@pakho ~]# awk -F: '{for(i=1;i<=10;i++){print $0}}'  passwd 

数组

一、定义数组

#需求:将用户名定义为数组的值,打印第一个值
[root@pakho ~]# awk -F: '{username[++i]=$1}END{print username[1]}' passwd 
root

二、数组遍历

#按索引遍历
[root@pakho ~]# awk -F: '{username[++i]=$1}END{for(i in username){print username[i]}}' passwd 
adm
lp
sync
shutdown
halt
mail
operator
root
bin
daemon

awk编程案例

#需求:统计/etc/passwd 中各种类型shell的数量
[root@pakho ~]# awk -F: '{shells[$NF]++}END{for(i in shells){print i,shells[i]}}' /etc/passwd
/bin/sync 1
/bin/bash 2
/sbin/nologin 22
/sbin/halt 1
/sbin/shutdown 1
#awk '/west/' datafile                      #找到west的行
#awk '/^north/'datafile                     #找north开头的行
#awk '$3 ~ /^north/' datafile               #第三列是好像是以north开头
#awk '/^(no|so)/' datafile                  #找no开头或者so开头的
#awk '{print $3,$2}' datafile               #打印第三列和第二列 ,是输出分隔符 默认输入空格
#awk '{print $3 $2}' datafile               #打印第三列和第二列 但没有空格
#awk '{print $0}' datafile                  #打印一行 每一行都打印出来
#awk 'END{print "总列数是:"NF}' datafile     #行处理之后打印行号
#awk '/northeast/{print $3,$2}' datafile    #打印出含有northeast的第三列和第二列
#awk '/E/' datafile                         #打印出含有E的行
#awk '$5 ~ /\\.[7-9]+/' datafile             #匹配第5列好像是以.7 .8 .9的 匹配多个
#awk '$2!~/E/{print $1,$2}' datafile        #匹配不是以E开头的行 打印第1列和第2列

以上是关于shell脚本——awk详细介绍(包含应用案例)的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本——正则表达式(包含grep详细介绍及应用)

自动化运维必须要学的Shell文本处理三剑客之——awk用法(超多案例详细介绍)

shell脚本四剑客之awk详解

shell脚本四剑客之awk详解

shell脚本应用正则表达式grep,sed,awk,的应用

shell脚本应用正则表达式grep,sed,awk,的应用