awk
一、awk
1. awk的工作原理
逐行读取文本,默认以空格或tab键为分隔符进行分割,将分割所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。
sed命令常用语一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。在使用awk命令的过程中,可以使用逻辑操作符“&&”表示“与”、“||”表示“或”、“!”表示“非”;还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。
2. 命令格式
awk 选项 '模式或条件 {操作}' 文件1 文件2 ……
awk -f 脚本文件 文件1 文件2 ……
3. awk常见的内建变量(可直接用)
内建变量 | 说明 |
---|---|
FS | 列分隔符。指定每行文本的字段分隔符,默认为空格或制表位。与“-F”作用相同 |
NF | 当前处理的行的字段个数 |
NR | 当前处理的行的行号(序数) |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
FILENAME | 被处理的文件名 |
RS | 行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是“\n” |
二、操作实例
1. 按行输出文本
awk '{print}' 文件名
输出所有内容
[root@localhost ~]# cat test.txt 11 22 33 44 [root@localhost ~]# awk '{print}' test.txt 11 22 33 44
awk '{print $0}' 文件名
输出所有内容
[root@localhost ~]# awk '{print $0}' test.txt 11 22 33 44
awk 'NR==n,NR==m {print}' 文件名
输出第n行至第m行的内容
[root@localhost ~]# awk 'NR==1,NR==3 {print $0}' test.txt 11 22 33
awk '(NR>=n) && (NR<=m) {print}' 文件名
输出第n行至第m行的内容
[root@localhost ~]# awk '(NR>=1) && (NR<=3) {print}' test.txt 11 22 33
awk 'NR==n || NR==m {print}' 文件名
输出第n行和第m行的内容
[root@localhost ~]# awk 'NR==1 || NR==3 {print}' test.txt 11 33
awk '(NR%2)==1 {print}' 文件名
输出所有奇数行的内容
[root@localhost ~]# awk '(NR%2)==1 {print}' test.txt 11 33
awk '(NR%2)==0 {print}' 文件名
输出所有偶数行的内容
[root@localhost ~]# awk '(NR%2)==1 {print}' test.txt 22 44
awk '/^a/ {print}' 文件名
输出以字符串a开头的行
[root@localhost ~]# awk '/^3/ {print}' test.txt 33
awk '/a$/ {print}' 文件名
输出以字符串a结尾的行
[root@localhost ~]# awk '/4$/ {print}' test.txt 44
awk 'BEGIN {x=0}; /^a/ {x++}; END {print x}' 文件名
输出文件中以字符串a开头行的数量
BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;awk再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句。
[root@localhost ~]# awk 'BEGIN{X=0}; /^root/ {x++}; END{print x}' /etc/passwd 1 [root@localhost ~]# awk 'BEGIN{X=0}; /nologin$/ {x++}; END{print x}' /etc/passwd 39
2. 按字段输出文本
awk -F ":" '{print $n}' 文件名
以:号为分隔符,输出每行的第n个字段
[root@localhost ~]# awk -F ":" '{print $1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail operator games ftp nobody systemd-network dbus polkitd abrt libstoragemgmt rpc colord saslauth setroubleshoot rtkit pulse qemu ntp radvd chrony tss usbmuxd geoclue sssd gdm rpcuser nfsnobody gnome-initial-setup avahi postfix sshd tcpdump 123456 named dhcpd apache
awk -F ":" '{print $n,$m}' 文件名
以:号为分隔符,输出每行的第n个和第m个字段
[root@localhost ~]# awk -F ":" '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12 ftp 14 nobody 99 systemd-network 192 dbus 81 polkitd 999 abrt 173 libstoragemgmt 998 rpc 32 colord 997 saslauth 996 setroubleshoot 995 rtkit 172 pulse 171 qemu 107 ntp 38 radvd 75 chrony 994 tss 59 usbmuxd 113 geoclue 993 sssd 992 gdm 42 rpcuser 29 nfsnobody 65534 gnome-initial-setup 991 avahi 70 postfix 89 sshd 74 tcpdump 72 123456 1000 named 25 dhcpd 177 apache 48
awk -F ":" '$n<m {print $n}' 文件名
以:号为分隔符,当第n个字段小于m时,输出第n个字段
[root@localhost ~]# awk -F ":" '$3<5 {print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4
awk -F ":" '!($n<m) {print}' 文件名
以:号为分隔符,当第n个字段不小于m时,输出整行内容
[root@localhost ~]# awk -F ":" '!($3<200) {print}' /etc/passwd polkitd:x:999:997:User for polkitd:/:/sbin/nologin libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin setroubleshoot:x:995:993::/var/lib/setroubleshoot:/sbin/nologin chrony:x:994:990::/var/lib/chrony:/sbin/nologin geoclue:x:993:988:User for geoclue:/var/lib/geoclue:/sbin/nologin sssd:x:992:987:User for sssd:/:/sbin/nologin nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin gnome-initial-setup:x:991:986::/run/gnome-initial-setup/:/sbin/nologin 123456:x:1000:1000:123456:/home/123456:/bin/bash
awk 'BEGIN {FS=":"}; {if ($n>=m) {print}}' 文件名
以:号为分隔符,当第n列大于等于m时,输出整行内容
[root@localhost ~]# awk 'BEGIN {FS=":"}; {if ($3>=1000) {print}}' /etc/passwd nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin 123456:x:1000:1000:123456:/home/123456:/bin/bash
awk -F ":" '{max=($n>=$m) ? $n : $m; {print max}}' 文件名
三元运算符。以:号为分隔符,如果第n个字段的值大于等于第m个字段的值,则把第n个字段的值赋给max,否则把第m个字段的值赋给max
[root@localhost ~]# awk -F ":" '{max=($3>=$4) ? $3 : $4; {print max}}' /etc/passwd 0 1 2 4 7 5 6 7 12 11 100 50 99 192 81 999 173 998 32 997 996 995 172 171 107 38 75 994 59 113 993 992 42 29 65534 991 70 89 74 72 1000 25 177 48
awk -F ":" '{print NR,$0}' 文件名
以:号为分隔符,处理每行内容和行号,没处理完一条记录,NR值加1
[root@localhost ~]# awk -F ":" '{print NR,$0}' /etc/passwd 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 8 halt:x:7:0:halt:/sbin:/sbin/halt 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 10 operator:x:11:0:operator:/root:/sbin/nologin 11 games:x:12:100:games:/usr/games:/sbin/nologin 12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin 13 nobody:x:99:99:Nobody:/:/sbin/nologin 14 systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin 15 dbus:x:81:81:System message bus:/:/sbin/nologin 16 polkitd:x:999:997:User for polkitd:/:/sbin/nologin 17 abrt:x:173:173::/etc/abrt:/sbin/nologin 18 libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin 19 rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin 20 colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin 21 saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin 22 setroubleshoot:x:995:993::/var/lib/setroubleshoot:/sbin/nologin 23 rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin 24 pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin 25 qemu:x:107:107:qemu user:/:/sbin/nologin 26 ntp:x:38:38::/etc/ntp:/sbin/nologin 27 radvd:x:75:75:radvd user:/:/sbin/nologin 28 chrony:x:994:990::/var/lib/chrony:/sbin/nologin 29 tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin 30 usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin 31 geoclue:x:993:988:User for geoclue:/var/lib/geoclue:/sbin/nologin 32 sssd:x:992:987:User for sssd:/:/sbin/nologin 33 gdm:x:42:42::/var/lib/gdm:/sbin/nologin 34 rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin 35 nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin 36 gnome-initial-setup:x:991:986::/run/gnome-initial-setup/:/sbin/nologin 37 avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin 38 postfix:x:89:89::/var/spool/postfix:/sbin/nologin 39 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin 40 tcpdump:x:72:72::/:/sbin/nologin 41 123456:x:1000:1000:123456:/home/123456:/bin/bash 42 named:x:25:25:Named:/var/named:/sbin/nologin 43 dhcpd:x:177:177:DHCP server:/:/sbin/nologin 44 apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
awk -F ":" '$n~ "a" {print $m}' 文件名
以:号为分隔符,输出第n个字段中含有字符串a的行的第m个字段
[root@localhost ~]# awk -F ":" '$7~ "/bash" {print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash 123456:x:1000:1000:123456:/home/123456:/bin/bash
awk -F ":" '($n~ "a") && (NF==m) {print}' 文件名
以:号为分隔符,输出第n个字段中含有字符串a且有m个字段的行
[root@localhost ~]# awk -F ":" '($1~ "root") && (NF==7) {print $1,$2}' /etc/passwd root x
awk -F “:” '($n != "a") && ($m != "b") {print}' 文件名
以:号为分隔符,输出第n个字段既不是字符串a也不是字符串b的行
[root@localhost ~]# awk -F ":" '($7!="/bin/bash")&&($7!="/sbin/nologin") {print}' /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt
通过管道、双引号调用Shell命令
echo $PATH | awk 'BEGIN{RS=":"}; END{print NR}'
以:号为分隔符,输出总字段数
[root@localhost ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin [root@localhost ~]# echo $PATH | awk 'BEGIN{RS=":"}; END{print NR}' 5
awk -F: '/a$/ {print | "wc -l"}' 文件名
以:号为分隔符,统计以字符串a为结尾的行的行数,同等于“grep -c”命令
[root@localhost ~]# awk -F: '/bash$/ {print | "wc -l"}' /etc/passwd 2 [root@localhost ~]# grep -c "/bash"$ /etc/passwd 2
free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
查看当前内存使用百分比
[root@localhost ~]# free -m total used free shared buff/cache available Mem: 1984 326 1257 9 400 1439 Swap: 4095 0 4095 [root@localhost ~]# free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}' 20%
top -b -n 1 | grep Cpu | awk -F "," '{print $4}' | awk '{print $1}'
查看当前CPU空闲率,"-b -n 1"表示只需要1次的输出结果
[root@localhost ~]# top -b -n 1 | grep Cpu | awk -F "," '{print $4}' | awk '{print $1}' 97.0
date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"
显示上次系统重启时间,等同于uptime;“second ago”为显示多少秒前的时间,+"%F %H:%M:%S"为时间格式,%F等同于%Y-%m-%d。
[root@localhost ~]# date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S" 2021-07-29 11:07:15
awk 'BEGIN {N=0; while ("w" | getline) n++; {print n=2}}'
调用w命令,并用来统计在线用户数
[root@localhost ~]# awk 'BEGIN {N=0; while ("w" | getline) n++; {print n=2}}' 2
awk 'BEGIN {"hostname" | getline; {print}}'
调用hostname,并输出当前的主机名
[root@localhost ~]# awk 'BEGIN {"hostname" | getline; {print}}' localhost.localdomain
注:当getline左右无重定向符“<”或“|”时,awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF,FNR和$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。
当getline左右有重定向符“<”或“|”时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。
FNR:awk当前读取的记录数,其变量值小于等于NR(比如当读取第二个文件时,FNR是从0开始重新计数,而NR不会),因此可使用“NR==FNR”来判断是否在读取第一个文件。
[root@localhost ~]# seq 10 | awk '{getline; print}' 2 4 6 8 10 [root@localhost ~]# seq 10 | awk '{print; getline}' 1 3 5 7 9
CPU使用率
[root@localhost ~]# cat cpu.sh #!/bin/bash cpu_us=`top -b -n 1 | grep Cpu | awk '{print $2}'` echo $cpu_us cpu_sy=`top -b -n 1 | grep Cpu | awk -F ',' '{print $2}' | awk '{print $1}'` echo $cpu_sy echo "$cpu_us+$cpu_sy" | bc [root@localhost ~]# ./cpu.sh 0.0 3.1 3.1
echo "A B C D" | awk '{OFS="|"; print $0 ;$1=$1; print $0}'
$1=$1是用来重新激活$0的重新赋值,也就是说每一个字段和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后面需要输出$0时这样做。
[root@localhost ~]# echo "A B C D" | awk '{OFS="|"; print $0 ;$1=$1; print $0}' A B C D A|B|C|D
3. awk数组循环
1.使用awk建立数组
awk 'BEGIN {a[0]=10; a[1]=20; print a[0]}'
awk 'BEGIN {a[0]=10; a[1]=20; print a[1]}'
[root@localhost ~]# awk 'BEGIN {a[0]=10; a[1]=20; print a[0]}' 10 [root@localhost ~]# awk 'BEGIN {a[0]=10; a[1]=20; print a[1]}' 20
awk 'BEGIN {a["abc"]=10; a["xyz"]=20; print a["abc"]}'
awk 'BEGIN {a["abc"]=10; a["xyz"]=20; print a["xyz"]}'
[root@localhost ~]# awk 'BEGIN {a["abc"]=10; a["xyz"]=20; print a["abc"]}' 10 [root@localhost ~]# awk 'BEGIN {a["abc"]=10; a["xyz"]=20; print a["xyz"]}' 20
awk 'BEGIN {a["abc"]="aabbcc"; a["xyz"]="xxyyzz"; print a["abc"]}'
awk 'BEGIN {a["abc"]="aabbcc"; a["xyz"]="xxyyzz"; print a["xyz"]}'
[root@localhost ~]# awk 'BEGIN {a["abc"]="aabbcc"; a["xyz"]="xxyyzz"; print a["abc"]}' aabbcc [root@localhost ~]# awk 'BEGIN {a["abc"]="aabbcc"; a["xyz"]="xxyyzz"; print a["xyz"]}' xxyyzz
awk 'BEGIN {a[0]=10; a[1]=20; a[2]=30; for (i in a) {print i,a[i]}}'
[root@localhost html]# awk 'BEGIN {a[0]=10; a[1]=20; a[2]=30; for (i in a) {print i,a[i]}}' 0 10 1 20 2 30
注1:BEGIN中的命令只执行一次
注2:awk数组的下标除了可以使用数字,也可以使用字符串,字符串需要使用双引号
- awk循环遍历
[root@localhost ~]# cat test1.txt aaa aaa bbb ccc aaa bbb aaa [root@localhost ~]# awk '{a[1]++} END{for(i in a) {print a[i]}}' test1.txt 7
注:a[1]初始为0,a[1]++后即为1,而这里awk中的a[1]++最终的值是由test1.txt文本内容有多少行决定的,文本逐行读取完毕后再执行END中的命令。
使用awk获取文件test1.txt中的重复行及次数
[root@localhost ~]# awk '{a[$1]++} END{for(i in a) {print a[i],i}}' test1.txt 4 aaa 1 ccc 2 bbb [root@localhost ~]# awk '{a[$1]++} END{for(i in a) {print a[i],i}}' test1.txt | sort -r 4 aaa 2 bbb 1 ccc
注:也可使用sort排序后通过“uniq -c”获取重复行次次数。以上操作是我们在日常工作中常用的运维手段,crontab日常监控以及排障时经常用得到。
扩展--运维工作常用的查看命令或文件
监控项目 | 监控命令或文件 |
---|---|
cpu负载 | uptime |
内存容量 | free -m |
硬盘空间 | df -h |
网卡流量 | ifconfig 网卡名称(如ens33) |
安装的软件包数量 | rpm -qa | wc -l |
账户数量 | /etc/passwd |
当前登录的账户数量 | who |
进程数量 | ps aux |
异常登录信息 | /var/log/secure |
例如:
使用awk统计httpd访问日志中每个客户端IP的出现次数
awk '{ip[$1]++} END{for (i in ip) {print ip[i],i}}' /var/log/httpd/access_log | sort -r
[root@localhost ~]# awk '{ip[$1]++} END{for (i in ip) {print ip[i],i}}' /var/log/httpd/access_log | sort -r 82 192.168.122.88
注:定义数组,数组名称为ip,数字的下标为日志文件的第1列(也就是客户端的IP地址),++的目的在于对客户端进行统计技术,客户端IP出现一次计数器就加1.END中的指令在读取完文件后执行,通过循环将所有统计信息输出,for循环遍历的是数组名ip的下标。
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章页面中给出作者和原文连接。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现