awk是一种编程语言,用于在linux\unix下对文本和数据进行处理,数据可以来自标准输入,一个或多个文件,或者其他命令输出。

目录

简介

它支持用户自定义函数和动态正则表达式等现金功能,是linux/unix下的强大编辑工具,在命令行使用,但更多的是作为脚本来使用。

awk的处理文本和数据的方式是这样的,

它逐行扫描文件,然后第一行到最后一行,寻找匹配的特定模式的行,并在这些行进你想要的的操作,如果没有指定动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理

awk是三个人的名字,一般使用的是gnu版本的awk。

语法格式

awk [option] 'commands' filename

awk [option] -f awk-scrip-file filename


= =options:

-F 定义输入字段分隔符,默认的分隔符是空格或者制表符tab


= =command:

BEGIN{}         {}              END{}
行处理前         行处理         行处理后

awk 'BEGIN{1/2} {print "ok"} END{print "。。。。。。"}' /etc/hosts
#输出
0.5
ok
ok
ok      #这里表示hosts有三行
......................

BEGIN{}         #通常用于定义一些变量,列如BEGIN{FS=":";OFS="---"}#FS这里修改成冒号分割,OFS为输出分隔符


= = awk命令格式:

awk 'pattern' filename          awk -F '/root/' /etc/passwd
awk '{action}' filename         awk -F":" '{print $1}' /etc/passwd
awk 'pattern {action}' filename awk -F '/root/{print $1}' /etc/passwd

command | awk 'pattern {action}'

awk工作原理

  • awk -F: ‘{print $1,$3}’ /etc/passwd
  • awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符作为结束
  • 然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始,最多达100个字段
  • awk如何知道用空格来分隔字段的呢,因为有一个内部变量FS来确定字段分隔符。初始时,FS赋值为空格
  • awk打印字段时,将以设置的方法使用print函数打印,awk在打印的字段间加上空格,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称之为输出字段分隔符OFS,OFS默认为空格
  • awk输出之后,从文件中获取另一行,并将其存储在$0中,覆盖原有的内容,然后将新的字符串分隔成字段并进行处理,该过程将持续到所有行处理完毕

= =记录与字段相关内部变量:man awk

$0 #awk变量$0保存当前记录内容    awk -F":" '{print $1}' /etc/passwd 完整的输入记录
NR #the total number of input records seen so far      awk -F":" '{print NR,$1}' /etc/passwd 行号, 已读的记录数,已经读出的记录数,就是行号,从1开始
            
            
FNR #the input record number in the current input file      awk -F":" '{print FNR,$0}' /et#c/passwd 多个文件可以看出
NF      #保存记录的字段数,$1,$2,$3 $NF是最后一个字段     awk -F: '{print $0,NF}' /etc/passwd  浏览记录的域的个数,一条记录的字段的数目
FS      #输入字段分隔符,默认空格        awk -F'[:\t]''{print $1,$2,$3}' /etc/passwd #指定分隔符多个 字段分隔符(默认是任何空格)
                                       awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd
OFS:    #输出字段分隔符 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符
                                        awk -F:'/alice/{print $1,$2,$3}' /etc/passwd
                                        awk 'BEGIN{FS=":";OFS="+++"}/^root/print{$1,$2,$3}' /etc/passwd
RS      #the input record separator,by default a newline #awk -F: 'BEGIN{RS=" "} {print $0}' a.txt   #记录分隔符。默认换行符 记录分隔符(默认是一个换行符)
ORS     #the output record separator ,by ddefault a newline      awk -F: 'BEGIN{ORS=""} {print $0}' passwd # 输出记录分隔符(默认值是一个换行符)

BEGIN{IGNORECASE=1} #忽略大小写

#FS字段分隔符=6  默认空格,可以-F":"进行赋初值
#   |
#$1 |$2
root:x:0:/:root:/ \n   #整行就是$0

bin:x:0:/:root:/ \n
#                 |
#                 RS记录分隔符
#NR=2,默认是换行符
#一行就是一个记录,一个记录有若干个字段


lab1:

        awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd     #将文件的每行输出成一行
        head -l /etc/passwd > passwd1   #将文件里的一行输出到passwd1文件中

格式化输出

  • print 函数

    date |awk '{print "Month" $2 "\nYear:" $NF}'
    awk -F:'{print "username is "$1"\t uid is:"  $3}' /etc/hosts       #\t tab键
    awk -F:'{print "\tusername and uid is:"#1,$3 "!"}' /etc/hosts
    
  • printf 函数

    awk -F: '{printf "%-15s %-10s %-15s\n",$1,$2,%3}' /etc/hosts
    awk -F: '{printf "|%-15s| %-10s |%-15s|\n",$1,$2,%3}' /etc/hosts        #输出好看
    %s 字符类型
    %d 数值类型
    %f 浮点型 
    占15字符
    -表示左对齐,默认是右对齐
    printf默认不会再行尾自动换行,加`\n`
    

awk模式或动作

任何awk语句都由模式和动作组成,模式部分决定动作语句何时触发及触发事件。处理及对数据进行操作。如果省略模式部分,动作将时刻保持执行状态,模式可以是任何条件语句,复合语句,正则表达式,模式包括两个特殊字段,BEGIN和END。使用BEGIN语句设置计数和打印头,BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文本开始执行,END语句用来在awk完成文本浏览动作后打印输出文本总是和结尾状态

  • 模式可以是:

= =正则表达式: 1. 匹配记录(整行):

awk '/^alice/' /etc/passwd
awk '$0~/^alice/' /etc/passwd
awk '!/alice' passwd
awk '$0!~/^alice/' /etc/passwd
  1. 匹配字段:匹配操作符(~ !~) (想到与列处理),可以是单字符匹配成功就行

    awk -F: '$1 ~/^alice/' /etc/passwd
    awk -F: '$NF !~/bash$/' /etc/passwd
    

= =比较表达式:

比较表达式采用对文本进行比较,只有当条件为真,财智星指定的动作。比较表达式使用关系运算符,用于比较数字和字符串

= =关系运算符 带" "表示字符串比较,不带如果是数字表示数字比大小

运算符          含义            实例
<               小于             x<y
<=              小于等于        x<=y
==              等于            x==y
!=             不等于          x!=y
>=              大于等于        x>=y
>               大于            x>y
df -P |grep '/' |awk '$4 > 25000'

= =条件表达式:

awk -F:'$3>300 {print $0}' /etc/passwd
awk -F:'{if($3>300) print $0}' /etc/passwd # {最外面的表示要行处理}
awk -F:'{if($3>300) {print $0}}' /etc/passwd
awk -F:'{if($3>300) {print $0} else{print $1}}' /etc/passwd

= =算数运算:+ - * / %(模)^(幂2^3)

可以在模式中执行计算,awk都将按浮点数方式执行算数运算

awk -F: '$3*10 >500' /etc/passwd
awk -F: '{if($3*10 >500){print $0}}' /etc/passwd

= =逻辑操作符和复合模式

&& 逻辑与 a&&b || 逻辑或 a||b ! 逻辑非 !a

awk -F: '$1~/root/ && $3<15' /etc/passwd #如果条件成立,打印整行

= =范围模式

awk '/Tom/,/Suzanne/' filename #从Tom到Suzanne

awk使用实例

awk '/west/' datafile #匹配west ,并输出,这种是pattern的使用,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)
awk '/^west/' datafile  #匹配west开头的行,并输出
awk '$3~/^west/' datafile #匹配$3以west开头的
awk '/^(no|so)/' datafile
awk '{print $3,$2}' datafile #加逗号默认两个输出之间有空格,不加默认挨在一起的

awk '{print $3 $2}' datafile
awk '{print $0}' datafile
awk '{print "number line of file is:"NF}' datafile #每一行输出有几段

awk '/northeast/{print $3 $2}' datafile #搜索datafiled有northeast关键字的所有行,并显示对应的shell,$3,$2
awk '/E/' datafile #有E时打印

awk '/^[ns]/{print $1}' datafile #以n或者s开头是打印$1

awk '$5 ~/\.[7-9]+/' datafile # 判断$5匹配到.后跟[7-9],+表示前字符出现1-多个时,打印

awk '$2 !~/E/{print $1,$2}' datafile

awk '$3 ~/^jolel/{print $1 "is a niec girl"}' datafile

awk '$8 ~/[0-9][0-9]$/{print $8}' datafile #以两个数字结尾的打印 第八列

awk '$4 ~/chun$/{print"is $"$8"."}' datafile #

awk '/Tj/{print $0}' datafile

awk '{print $1}' /etc/passwd #打印整行,分隔符为空格

awk -F: '{print $1}' /etc/passwd #打印第一列。分隔符为:指定特定的分隔符,查询第一列

awk '{print "number is "NF}' /etc/passwd #换行符为分隔符,所以打印1

awk -F"[ :]"'{print NF}' /etc/passwd #这里有个空格还有冒号,[ :]+时可以有多个冒号,这时算一个 

awk -F ":" '{print $NF}' /etc/passwd #指定特定的分隔符,查询最后一列

awk '$7==5' datafile
awk '$7=="ct"{print $1,$2}' datafile #如果$7==ct,输出
awk '$7!=5' datafile

awk -F: 'NR==2{print "filename: "FILENAME, $0}' /etc/passwd #打印/etc/passwd/的第二行信息

ifconfig |grep eth* | awk -F '[ ]+' '{print $1}' 利用正则过滤多个空格

awk脚本编程

条件判断

#if语句
awk -F: '{if(表达式){语句1;2;3} else if{语句1;2;3} if{语句1;2;3}}' #行处理要加最外面大括号
awk -F: '{if($3>0&&$3<1000){cnt++} END{print cnt}}' #行处理要加最外面大括号
awk 'BEGIN{i=1;while(i<7){print i}}'

cat b.txt

111 222
333 444 555
666 777 888 999

awk '{i=1;while(i<NF){print $i;i++}}' b.txt #依次打印某一列
111
222
333
。。。
999

## 数组的处理

数组的处理

awk -F: '{username[++i]=$1} END {print unsername[1]}' /etc/datafile #将某一个字段赋值,i++从0开始,++i从1开始

awk -F: '{username[j++]=$1} END {for(i in username){print i,unsername[i]} }' /etc/datafile #i里面是数组的索引

脚本联系

#统计shell类型,把统计的对象作为数组的索引---i,三次握手,4次挥手
awk -F:'{{shells[$NF]++} END{ for(i in shells) { print i,shells[i]}  }} '

#统计tcp连接状态,把统计的对象作为数组的索引---i,当前事实状态 netstat ;-ant,其中t表示tcp,可以是u,dup,也可以将netstat换成ss,状态会变成第二列
 netstat -ant | grep :80 | awk '{shells[$NF]++} END{ for(i in shells) { print i,shells[i]}  }} ' | sort -k2 -n |head 
 #输出:
 #listen:1
 #establish:20
 #顺序排列-n,-nr为逆序排列从大到小,-k2表示表示第二列排序,head表示显示前十个,或者head -5 打印前五个

总结,统计啥(某一字段),就把啥作为索引,然后++

ss -an |grep :80 |awk -F: '!/LISTEN/{ips[$(NF-1)]++} END{for(i in ips){print i,ips{i}}}'|sort -k2 -nr |head
#这里去掉了包含LISTEN行

#统计某一天的pv量<统计日志>
#

grep '07/aug/2020' /etc/logfile |wc -l
#wc
#c或--bytes或--chars 只显示Bytes数。在默认的情况下,wc将计算指定文件的行数、字数,以及字节数
#-l或--lines 只显示行数。
#-w或--words 只显示字数。
#--help 在线帮助。
#--version 显示版本信息。
#wc testfile           # testfile文件的统计信息 
#3 92 598 testfile       # testfile文件的行数为3、单词数92、字节数598 


#这里要转义一下某一字段的\好,先写结构
awk '/22\/mar\/2001/{ips[$1]++} END{for(i in ips){print i ips[i]}' logfile

awk内置函数

#统计用户名为4个字符的用户
awk -F: '$1~/^....$/{cont++;print $1} END{print "cnt is :"cont}' userfile

##########这里用到了lenth函数
awk -F 'lenth($1)==4{cont++;print $1} END{print "cnt is :"cont}' userfile

#awk使用外部变量

##########sub只查找替换第一个,gsub是全局的
var="hello"
echo "hellp" |awk 'gsub(/hellp/,$var)'#错 
echo "hellp" |awk "gsub(/hellp/,$var)"#错
#方法1,在双引号情况下使用
echo "hellp" |awk "gsub(/hellp/,\"$var\")"      #可以替换
#方法2,在单引号情况下使用
echo "hellp" |awk 'gsub(/hellp/,"'"$var"'")'    #可以替换,'''$var'''也可以
##########这里注意加了个int内置函数
df -h |awk '{if(int($5)>5){print $6:$5}}'

########方法3,awk -v参数
echo "hellp" |awk -v var="hello" -F: 'gsub(/hellp/,var)'

总结

学完这个命令可以进行自我学习 1. 获取网卡ip 2. 获得内存使用情况 3. 获得磁盘使用情况 4. 清空本机的ARP缓存 5. 打印出/etc/host文件的最后一个字段{按空格分隔} 6. 打印指定目录下的目录名