awk基本用法 淡淡的烟草味﹌ 2022-05-21 12:14 176阅读 0赞 ### **shell 脚本编程** ### \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 回顾: sed 文本编辑器,逐行处理,非交互 sed \[选项\] ‘条件指令’ 文件 选项: \-n 屏蔽默认输出 \-i 修改原文件 \-r 支持扩展正则 条件:行号,/正则/ 指令:增删改查 a 行前面写入 i 行后面写入 d 删除行 dd s s/旧// 变相删除 c 修改行3c /root/c s s/旧/新/ p 打印、输出 r 导入 w 导出 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# sed 复制剪切: H 追加 复制 ; h 覆盖 复制 G 追加 粘贴 ; g 覆盖 粘贴 sed -n ‘3h;6g’ a.txt 复制第3行内容覆盖插入到第6行 (原本的第6行没了) sed -n ‘3h;6G’ a.txt 复制第3行内容插入到第6行下面 (原本的第6行还在) sed -n ‘3H;6g’ a.txt 复制第3行内容覆盖插入到第6行并先空一行(原本的第6行没了) sed -n ‘3H;6G’ a.txt 复制第3行内容插入到第6行下面并先空一行 (原本的第6行还在) \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# ### 一、**awk基本用法 ** ### ### **1.awk命令解析** ### 1)主要用法 awk 功能与grep类似,比grep功能多 awk 原理和语法格式与sed类似 awk \[选项\] ‘条件\{ 指令\}’ 文件 多条命令用分号隔开;print是最常用的指令; 没有指令默认为打印全部符合条件的内容 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 例如:取每一行的第三个字:awk ‘\{print $3\}’ a.txt 输出内存大小(注意内存会实时变化):free | awk ‘/Mem/\{print $4\}’ 提取根分区剩余容量df;内存剩余容量free;cpu负载uptime(最近1、5、15分钟负载,相当于top的第一行)(linux允许超负载);网卡流量ifconfig(RX 发送包,TX接受包); num=\`df | awk '/\\/$/\{print $4\}'\` (以根结尾的) df -hT / | tail -1 | awk '\{print $6\}' free | awk '/Mem/\{print $4\}' uptime | awk '\{print $10\}' ifconfig enp2s0 | awk ‘/pack/\{print $5\}’ ==ifconfig enp2s0 | grep "inet " | awk '\{print $2\}' \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 网页实时更新根分区剩余容量、内存剩余容量、CPU负载、网卡流量等 yum -y install httpd systemctl restart/enable vim a.txt echo 'Content-Type:text/html' echo '' echo '' echo "根分区剩余容量为:" df | awk '/\\/$/\{print $4\}' echo "</br>" echo "内存剩余容量为:" free | awk '/Mem/\{print $4\}' echo "</br>" echo "CPU负载为:" uptime | awk '\{print $8,$9,$10\}' echo "</br>" echo "网卡流量为:" ifconfig enp2s0 | awk '/pack/\{print $5\}' echo "</br>" 脚本存放位置:/var/www/cgi-bin ,给个x权限,每刷新下网页脚本就会运行下;关闭selinux;刷新网页F5; firefox http://172.40.55.11x/cgi-bin/test.sh \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 筛选不以空格分隔的文档 \-F :指定分隔符(不写默认为空格或tab键) 指定分隔符为冒号: awk -F: '/^roo/\{print $1,$2,$3,$4,$5\}' /etc/passwd awk的内置变量: $0 一整行(全文) $1 第1列 ; $2 第2列 ... ... NF 当前行有几列,逐行处理(列数) NR 当前行的行号(行数) FNR 记录当前处理行在原文本内的序号(行号) FS 保存或设置分隔符,FS=“:” awk '\{print NF\}' a.txt \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# tailf /var/log/secure 回车<屏幕变空白> 其他主机:ssh 该虚拟机 <输入错误密码> 对公网开放防止远程登录及破解密码:找出登录失败的ip,并放入防火墙 while : do if 在里面就不再导了 awk ‘/Failed/\{print $11\}’ /var/log/secure | grep -v “\[a-Z\]” >>ip.txt for i in $(cat ip.txt) do 加到防火墙 done sleep 300 done \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 支持直接常量,常量变量混搭: awk -F: ‘\{print “hello”,$1\}’ /etc/passwd /这个文件有多少行就输出多少次,双引号,hello+用户名 awk 完整语法:可以单独使用,也可以一起使用 awk ‘BEGIN\{\} 条件\{\} END\{\}’ 文件 begin\{\} 后面的命令,在读取文件内容之前执行,只执行一次 /初始化 条件\{\} 读取文件的过程中执行,执行n次(文件的行数) /处理 END\{\} 读取文件的过程后执行,只执行一次 /总结 awk ‘BEGIN\{i=0\} /\[0-9\]/\{i++\} END\{print i\}’ 文件 awk 'BEGIN\{x=0\}/\\<bash$/\{x++\} END\{print x\}' /etc/passwd == egrep -c '\\<bash$' /etc/passwd /-c统计匹配的行数 awk ‘BEGIN\{x=1.2;print x/2\} /可以做算术运算 awk ‘BEGIN\{print 1000/2\} /可以常量或变量 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 分析能登录计算机的用户有多少?(有bash解释器) awk ‘BEGIN\{i=0\} /bash$/\{i++\} END\{print i\}’ /etc/passwd awk的变量不用定义,可以直接调用。默认字串:空;初始数值:0 awk ‘ /bash$/\{i++\} END\{print i\}’ /etc/passwd \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 用户名 UID Shell root 0 /bin/bash user1 500 /sbin/nologin 总共用户量:xx (\\t tab键) awk -F ‘BEGIN\{print “用户名\\tUID\\tshell”\} /bash$/\{print $1”\\t”$3”\\t”$7;x++\} END\{print “总共用户量:”,x\}’ /etc/passwd awk -F: 'BEGIN\{print "User\\tUID\\tHome"\} \{print $1"\\t"$3"\\t"$6\} END\{print "Total"NR"lines."\}' /etc/passwd \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# (UID/GID范围: cat /etc/login.defs ; ~包含 ;) 条件的表现形式:正则表达式、数值/字符串比较、逻辑比较、运算符 模糊匹配:awk -F: ‘$1~/root/\{print $1\}’ /仅对第一列匹配(正则包含即可) 精确匹配:awk -F: ‘$1==”root“\{print $1\}’ 精确匹配:awk -F: ‘$3>=1000\{print $1\}’ NR==2 当前行为第二行 NF>=2 包含两个及以上字段的行 awk -F: ‘$3>1000||$3<10’ /etc/passwd /支持&&和|| \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 练习:ftp://172.40.50.118/share/shell/SHELL/ awk\_exam.pdf grade.txt 显示不包含 Brown 的行 awk '$0 !~ /Brown/' grade.txt 当第一列的第四个字符是 a 时,显示该行 awk '$1 ~/^...a/' grade.txt 当第六列大于第七列是,显示$6 大于 $7 awk '$6 > $7 \{print $6,"大于",$7\}' grade.txt 显示包含 Yellow 或 Brown 的行 awk '$0 ~/(Yellow|Brown)/' grade.txt awk '$0 ~/Yellow/||/Brown/' grade.tx 显示文档第一列、第六列、第七列,如果第一列是 M.Tansley,则先将其第六列的值减 1 后再输出 awk '\{if($1=="M.Tansley") $6=$6-1; print $1,$6,$7\}' grade.txt awk /San/ data.txt 显示包含San的行 列出UID间于501~505的用户详细信息 \# awk -F: ‘($3>=501)&&($3<=505)’ /etc/passwd 输出/etc/hosts文件内以127或192开头的记录 \# awk '/^(172|127)/' /etc/hosts 或 awk '/^127/||/^172/' /etc/hosts 列出100以内整数中7的倍数或是含7的数 \# seq 100 | awk ‘/7/||$1%7==0’ seq 100 | awk 'NR%7==0||NR~/7/' seq 100 | awk '$0%7==0||$0~/7/' seq 100 | awk '$1%7==0||$1~/7/' \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 综合应用 找到使用bash作登录Shell的本地用户 1.从passwd里把能登录的用户提取出来 2.从shadow里把他们的密码取出来 \#!/bin/bash user=\`awk -F: ‘/bash$/\{print $1\}’ /etc/passwd\` /注意反引号 for i in $user do awk -F: -v x=$i ‘$1==x\{print $1,$2\}’ /etc/shadow done \-v 调用外部shell变量 awk -v x=10 ‘\{print x\}’ /etc/hosts /加文件以逐行处理 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# awk -F: '\{print $1","$7\}' passwd.txt 输出第3行(行号NR等于3)的用户记录:awk -F: 'NR==3' passwd.txt 输出奇数行(行号NR除以2余数为1)的用户记录:awk -F: 'NR%2==1' passwd.txt 输出前3行文本:awk -F: 'NR<=3' passwd.txt 输出从第5行开始到文件末尾的所有行:awk -F: 'NR>=5' passwd.txt 输出UID小于3或者UID是偶数的用户记录: awk -F: '$3<=3||$3%2==0' passwd.txt 输出当前用户的用户名、宿主目录、登录Shell信息: awk -F: '$1==ENVIRON\["USER"\]\{print $1,$6,$7\}' passwd.txt \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# day07 awk:编程语言 回顾: awk数据过滤软件(grep) 处理列【条件:/正则/,字符,数字,&&,||】 awk ‘BEGIN\{\} 条件\{\} END\{\}’ 文件 == != >= > < <= -eq -gt -ge shell awk -F: ‘/root/\{print $1,$3\}’ passwd awk -F: ‘$1==’root’\{print $1,$3\}’ passwd \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# awk的if语句 if(判断)\{\} if()\{\} else\{\} ; if()\{\} else if()\{\} else\{\} awk ‘BEGIN\{if..\} 条件\{if..\} END\{if..\}’ 文件 awk对空格没严格要求,不识别单引号 统计/etc/passwd文件中UID小于或等于500的用户个数: awk -F: 'BEGIN\{i=0\}\{if($3<=500)\{i++\}\}END\{print i\}' /etc/passwd 分别统计/etc/passwd文件中UID小于或等于500、UID大于500的用户个数: awk -F: 'BEGIN\{i=0;j=0\} \{ if($7~/bash$/)\{i++\} else\{j++\} \} END\{print i,j\}' /etc/passwd 分别统计/etc/passwd文件中登录Shell是“/bin/bash”、“/sbin/nologin”、其他的用户个数: awk -F: 'BEGIN\{i=0;j=0;k=0\} \{if($7~/bash$/)\{i++\}else if($7~/nologin$/)\{j++\}else\{k++\}\} END\{print i,j,k\}' /etc/passwd \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# awk的while循环 while()\{\} awk ‘BEGIN\{while..\} 条件\{while..\} END\{while..\}’ 文件 求词频: 以“:”或“/”做分隔,针对每一行的每一列进行比对,如果包含“root”,则次数加1。其中,逐行处理直接由awk完成,逐列处理交给while循环,通过i变量依次取$1、$2、……、$NF进行检查;变量j在预处理时赋值0,没匹配一个字段加1。 awk -F \[:/\] 'BEGIN\{j=0\}\{i=1\} \{while(i<=NF)\{if($i~/root/)\{j++\};i++\}\} END\{print j\}' /etc/passwd awk -F \[:/\] ' \{i=1; while(i<=NF)\{if($i~/root/)\{j++\};i++\}\} END\{print j\}' /etc/passwd echo $(cat /etc/passwd) | awk -F "root" '\{print NF-1\}' \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# awk的数组、for循环 awk的下标可以是数字或字串;awk的下标可以不定义; awk \{a\[0\]=11;a\[2\]=88; print a\[0\],a\[2\]\} awk \{a\[nihao\]=11;a\[chen\]=88; print a\[0\],a\[2\]\} 公式:(除$1外,其他都不变) awk '\{ip\[$1\]++\}’ /IP\[$1\]数组变量 who | awk '\{ip\[$1\]++\} END\{for(i in ip) \{print i,ip\[i\]\}\}' /看用户登录情况 awk '\{ip\[$1\]++\} END\{for(i in ip) \{print i,ip\[i\]\}\}' /var/log/httpd/access\_log 分析Web日志的访问量排名,要求获得客户机的地址、访问次数,并且按照访问次数排名 针对文本排序输出可以采用sort命令,相关的常见选项为\-r、\-n、\-k。其中\-n表示按数字顺序升序排列,而\-r表示反序,\-k可以指定按第几个字段来排序。 awk '\{ip\[$1\]++\} END\{for(i in ip) \{print i,ip\[i\]\}\}' /var/log/httpd/access\_log | sort -nr -k 2 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# 准备工作: 服务端:(真机) yum -y install httpd systemctl start httpd ls -lh /var/log/httpd/access\_log wc -l /var/log/httpd/access\_log curl http://192.168.4.254/ /自己访问自己 客户机: yum -y install httpd-tools ab -c 100 -n 10000 http://192.168.4.254/ /ab最大并发2万次 DOS攻击【deny of service】 回服务端:(svr7) vim /var/log/httpd/access\_log wc -l /var/log/httpd/access\_log /对比 ls -lh /var/log/httpd/access\_log /对比字节 \#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# Top # **NSD SHELL DAY06** # 案例1:使用awk提取文本 案例2:awk处理条件 案例3:awk综合脚本应用 案例4:awk流程控制 案例5:awk扩展应用 ## **1 案例1:使用awk提取文本** ## ### **1.1 问题** ### 本案例要求使用awk工具完成下列过滤任务: 练习awk工具的基本用法 提取本机的IP地址、根分区使用率 格式化输出/etc/passwd文件中的用户名、UID、宿主目录信息 格式化输出passwd文件内容时,要求第一行为列表标题,最后一行提示一共已处理文本的总行数,如图-1所示。 图\-1 ### **1.2 步骤** ### 实现此案例需要按照如下步骤进行。 步骤一:awk文本过滤的基本用法 1)基本操作方法 格式:awk \[选项\] '\[条件\]\{编辑指令\}' 文件 其中,print 是最常用的编辑指令;若有多条编辑指令,可用分号分隔。 处理文本时,若未指定分隔符,则默认将空格、制表符等作为分隔符。 直接过滤文件内容: \[root@svr5 ~\]\# awk '\{print $1,$2\}' /etc/rc.local //输出文件的第1、2列 \#!/bin/sh \# \# This \# You \# want touch /var/lock/subsys/local 结合管道过滤命令输出: \[root@svr5 ~\]\# uname -a //正常的完整输出 Linux svr5.tarena.com 2.6.18-348.el5 \#1 SMP Wed Nov 28 21:22:00 EST 2012 x86\_64 x86\_64 x86\_64 GNU/Linux \[root@svr5 ~\]\# uname -a | awk '\{print $1,$3,$12\}' //输出第1、3、12字段 Linux 2.6.18-348.el5 x86\_64 2)选项 -F 可指定分隔符 截取/etc/passwd文件的前7行,用来创建一个测试文件,操作如下: \[root@svr5 ~\]\# head -7 /etc/passwd > passwd.txt \[root@svr5 ~\]\# cat passwd.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 输出passwd.txt文件中以分号分隔的第1、7个字段,显示的不同字段之间以逗号隔开,操作如下: \[root@svr5 ~\]\# awk -F: '\{print $1","$7\}' passwd.txt root,/bin/bash bin,/sbin/nologin daemon,/sbin/nologin adm,/sbin/nologin lp,/sbin/nologin sync,/bin/sync shutdown,/sbin/shutdown 或者: \[root@svr5 ~\]\# awk -F ":" '\{print $1","$7\}' passwd.txt root,/bin/bash bin,/sbin/nologin daemon,/sbin/nologin adm,/sbin/nologin lp,/sbin/nologin sync,/bin/sync shutdown,/sbin/shutdown awk还识别多种单个的字符,比如以“:”或“/”分隔,输出第1、10个字段: \[root@svr5 ~\]\# awk -F \[:/\] '\{print $1,$10\}' passwd.txt root bash bin nologin daemon nologin adm sbin lp sync sync shutdown shutdown 输出每次处理的行号,以及当前行以“:”分隔的字段个数: \[root@svr5 ~\]\# awk -F: '\{print NR,NF\}' passwd.txt 1 7 2 7 3 7 4 7 5 7 6 7 7 7 3)awk处理的时机 awk会逐行处理文本,支持在处理第一行之前做一些准备工作,以及在处理完最后一行之后做一些总结性质的工作。在命令格式上分别体现如下: 行前处理,BEGIN\{ \} 逐行处理,\{ \} 行后处理,END\{ \} 上述编辑指令段可以包含在一对单引号内,比如: awk \[选项\] ' BEGIN\{ 编辑指令 \} \{ 编辑指令\} END\{ 编辑指令\}' 文件 只做预处理的时候,可以没有操作文件,比如: \[root@svr5 ~\]\# awk 'BEGIN\{A=1024;print A\*2.56\}' 2621.44 举个包括三个处理时机的例子——“统计系统中使用bash作为登录Shell的用户总个数:预处理时赋值变量x=0,然后逐行读入 /etc/passwd文件检查,如果发现登录Shell是/bin/bash则x增加1,全部处理完毕后,输出x的值即可。相关操作及结果如下: \[root@svr5 ~\]\# awk 'BEGIN\{x=0\}/\\<bash$/\{x++\} END\{print x\}' /etc/passwd 29 当然,这个例子比较简单(效果与egrep -c '\\<bash$' /etc/passwd 相同),此处仅仅是用来说明awk三种处理时机的用法。在实际工作中,利用awk的这种处理流程可以完成许多更复杂的任务。 步骤二:利用awk提取本机的IP地址、根分区使用率 1)提取IP地址 分步实现的思路及操作参考如下—— 通过ifconfig eth0查看网卡信息,其中包括IP地址: \[root@svr5 ~\]\# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:0C:29:82:09:E9 inet addr:192.168.4.4 Bcast:192.168.4.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fe82:9e9/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:358524 errors:0 dropped:0 overruns:0 frame:0 TX packets:230638 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:44470760 (42.4 MiB) TX bytes:64236279 (61.2 MiB) 结合grep获得包含IP地址的那一行: \[root@svr5 ~\]\# ifconfig eth0 | grep "inet addr:" inet addr:192.168.4.4 Bcast:192.168.4.255 Mask:255.255.255.0 再结合awk过滤出默认分隔的第2列: \[root@svr5 ~\]\# ifconfig eth0 | grep "inet addr:" | awk '\{print $2\}' addr:192.168.4.4 进一步结合awk过滤出以“:”分隔的第2列: \[root@svr5 ~\]\# ifconfig eth0 | grep "inet addr:" | awk '\{print $2\}' | awk -F: '\{print $2\}' 192.168.4.4 2)提取根分区使用率 分步实现的思路及操作参考如下—— 通过df命令查看根分区的使用情况,其中包括使用率: \[root@svr5 ~\]\# df -hT / 文件系统 类型 容量 已用 可用 已用% 挂载点 /dev/sda2 ext3 19G 7.2G 11G 40% / 输出上述结果中最后一行的第6列: \[root@svr5 ~\]\# df -hT / | tail -1 | awk '\{print $6\}' 40% 步骤三:格式化输出/etc/passwd文件 1)任务需求及实现思路分析 根据任务要求的结果,输出的内容包括三个部分:列表头、用户信息、列表尾。 由于/etc/passwd文件中的用户记录是单一的以“:”分隔,而且恰好awk本身就已经支持“前、中、后”三段式处理,所以用awk处理是再合适不过了。通过awk的内置变量NR即可获得处理的记录行数,因此只要设置正确的输出即可。 2)根据实现思路编写、验证awk过滤语句 输出信息时,可以使用“\\t”显示Tab制表位: \[root@svr5 ~\]\# awk -F: 'BEGIN\{print "User\\tUID\\tHome"\} \\ \{print $1"\\t"$3"\\t"$6\} END\{print "Total "NR" lines."\}' /etc/passwd User UID Home root 0 /root bin 1 /bin daemon 2 /sbin adm 3 /var/adm lp 4 /var/spool/lpd sync 5 /sbin .. .. iamkiller 1234 /opt/.private/iamkiller nsd001 0 /home/nsd001 nsd002 1236 /home/nsd002 nsd003 1237 /home/nsd003 postfix 89 /var/spool/postfix Total 67 lines. ## **2 案例2:awk处理条件** ## ### **2.1 问题** ### 本案例要求使用awk工具完成下列过滤任务,注意awk处理条件的设置: 列出UID间于501~505的用户详细信息 输出/etc/hosts文件内以127或192开头的记录 列出100以内整数中7的倍数或是含7的数 ### **2.2 步骤** ### 实现此案例需要按照如下步骤进行。 步骤一:认识awk处理条件的设置 创建测试文件passwd.txt文件: \[root@svr5 ~\]\# head -7 /etc/passwd > passwd.txt \[root@svr5 ~\]\# cat passwd.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 1)使用正则表达式设置条件 输出其中以bash结尾的完整记录: \[root@svr5 ~\]\# awk -F: '/bash$/\{print\}' passwd.txt root:x:0:0:root:/root:/bin/bash 输出以a、b、c或d开头的用户名、宿主目录: \[root@svr5 ~\]\# awk -F: '/^\[a-d\]/\{print $1,$6\}' passwd.txt bin /bin daemon /sbin adm /var/adm 输出其中用户名以a开头、登录Shell以nologin结尾的用户名、登录Shell: \[root@svr5 ~\]\# awk -F: '/^a|nologin$/\{print $1,$7\}' passwd.txt bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin 输出其中宿主目录以bin结尾(对第6个字段做~匹配)的用户名、宿主目录信息: \[root@svr5 ~\]\# awk -F: '$6~/bin$/\{print $1,$6\}' passwd.txt bin /bin daemon /sbin sync /sbin shutdown /sbin 输出其中登录Shell不以nologin结尾(对第7个字段做!~反向匹配)的用户名、登录Shell信息: \[root@svr5 ~\]\# awk -F: '$7!~/nologin$/\{print $1,$7\}' passwd.txt root /bin/bash sync /bin/sync shutdown /sbin/shutdown 2)使用数值/字符串比较设置条件 输出第3行(行号NR等于3)的用户记录: \[root@svr5 ~\]\# awk -F: 'NR==3\{print\}' passwd.txt daemon:x:2:2:daemon:/sbin:/sbin/nologin 输出奇数行(行号NR除以2余数为1)的用户记录: \[root@svr5 ~\]\# awk -F: 'NR%2==1\{print\}' passwd.txt root:x:0:0:root:/root:/bin/bash daemon:x:2:2:daemon:/sbin:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 输出偶数行(行号NR除以2余数为0)的用户记录: \[root@svr5 ~\]\# awk -F: 'NR%2==0\{print\}' passwd.txt bin:x:1:1:bin:/bin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync 输出前3行文本: \[root@svr5 ~\]\# awk -F: 'NR<=3\{print\}' passwd.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin 输出从第5行开始到文件末尾的所有行: \[root@svr5 ~\]\# awk -F: 'NR>=5\{print\}' passwd.txt lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 输出用户名为“sync”的行: \[root@svr5 ~\]\# awk -F: '$1=="sync"\{print\}' passwd.txt sync:x:5:0:sync:/sbin:/bin/sync 输出当前用户的用户名、宿主目录、登录Shell信息: \[root@svr5 ~\]\# awk -F: '$1==ENVIRON\["USER"\]\{print $1,$6,$7\}' passwd.txt root /root /bin/bash 3)逻辑测试条件 输出第3~5行文本: \[root@svr5 ~\]\# awk -F: 'NR>=3&&NR<=5\{print\}' passwd.txt daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 严谨一点可以写成: \[root@svr5 ~\]\# awk -F: '(NR>=3)&&(NR<=5)\{print\}' passwd.txt daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 输出第3行和第5行文本: \[root@svr5 ~\]\# awk -F: 'NR==3||NR==5\{print\}' passwd.txt daemon:x:2:2:daemon:/sbin:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 输出“登录Shell不以nologin结尾”或者“用户名以a或d开头”的文本: \[root@svr5 ~\]\# awk -F: '$7!~/nologin$/||$1~/^\[ad\]/\{print\}' passwd.txt root:x:0:0:root:/root:/bin/bash daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 输出UID小于3或者UID是偶数的用户记录: \[root@svr5 ~\]\# awk -F: '$3<3||$3%2==0\{print\}' passwd.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 4)数学运算 以统计passwd.txt文件中以“:”分隔的总字段个数,需要每处理一行时将当前行的字段数(内置变量NF)计和,因此可在BEGIN时定义一个初始变量,过程称求和,最后在END时输出结果。 相关操作及结果如下(共49个字段): \[root@svr5 ~\]\# awk -F: 'BEGIN\{x=0\}\\ \{x+=NF\} END\{print "Total "x" fields."\}' passwd.txt Total 49 fields. 步骤二:完成任务要求的awk过滤操作 1)列出UID间于501~505的用户详细信息: \[root@svr5 ~\]\# awk -F: '$3>=501&&$3<=505\{print\}' /etc/passwd hunter:x:501:501::/home/hunter:/bin/bash vina:x:502:502::/home/vina:/bin/bash kdev:x:503:503::/home/kdev:/bin/bash zengye:x:504:504::/home/zengye:/bin/bash stu01:x:505:1201::/tech/nsdhome/stu01:/bin/bash 2)输出/etc/hosts映射文件内以127或者192开头的记录: \[root@svr5 ~\]\# awk -F: '/^127|^192/\{print\}' /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 192.168.4.5 svr5.tarena.com svr5 3)列出100以内整数中7的倍数或是含7的数: 此操作无处理文件,正常思路应该是用Shell循环来完成;因为要求用awk来实现,如果不用循环,则根据逐行处理的思路,应该提供一个100行的文本对象,然后将行号作为处理的整数,逐个判断并输出即可。 利用seq命令可生成1-100的整数序列,比如: \[root@svr5 ~\]\# seq 100 1 2 3 4 5 6 7 8 9 10 .. .. 结合管道交给awk处理,可以简化实现步骤。针对本任务而言,行号与每行的实际文本值是一致的,那么根据NR或者$0行值进行判断都是可以的。输出100以内7的倍数或是包含7的数: \[root@svr5 ~\]\# seq 100 | awk 'NR%7==0||NR~/7/\{print\}' 7 14 17 21 27 28 35 37 42 47 .. .. 或者: \[root@svr5 ~\]\# seq 100 | awk '$0%7==0||$0~/7/\{print\}' 7 14 17 21 27 28 35 37 42 47 .. .. ## **3 案例3:awk综合脚本应用** ## ### **3.1 问题** ### 本案例要求编写脚本getupwd-awk.sh,实现以下需求: 找到使用bash作登录Shell的本地用户 列出这些用户的shadow密码记录 按每行“用户名 \--> 密码记录”保存到getupwd.log,如图\-2所示 图-2 ### **3.2 步骤** ### 实现此案例需要按照如下步骤进行。 步骤一:任务需求及思路分析 编写getupwd-awk.sh脚本的任务要求如下: 分析出使用bash作登录Shell的本地用户 列出这些用户的shadow密码记录 按每行“用户名 \-- 密码记录”保存结果 步骤二:根据实现思路编写脚本 复制原getupwd.sh脚本,生成getupwd-awk.sh: \[root@svr5 ~\]\# cat getupwd.sh //确认原脚本内容 \#/bin/bash > /tmp/getupwd.log \#\# 创建空文件 sed -n '/:\\/bin\\/bash$/w /tmp/urec.tmp' /etc/passwd \#\# 提取符合条件的账号记录 UNUM=$(egrep -c '.' /tmp/urec.tmp) \#\# 取得记录个数 while \[ $\{i:=1\} -le $UNUM \] \#\# 从第1行开始,遍历账号记录 do UREC=$(sed -n "$\{i\}p" /tmp/urec.tmp) \#\# 取指定行数的记录 NAME=$\{UREC%%:\*\} \#\# 截取用户名(记录去尾) PREC=$(sed -n "/^$NAME:/p" /etc/shadow) \#\# 查找与用户名对应的密码记录 PASS=$\{PREC\#\*:\} \#\# 掐头 PASS=$\{PASS%%:\*\} \#\# 去尾,只留下密码记录 echo "$NAME --> $PASS" >> /tmp/getupwd.log \#\# 保存结果 let i++ \#\# 自增1,转下一次循环 done /bin/rm -rf /tmp/urec.tmp \#\# 删除临时文件 echo "用户分析完毕,请查阅文件 /tmp/getupwd.log" \#\# 完成后提示 \[root@svr5 ~\]\# cp getupwd.sh getupwd-awk.sh //复制为新脚本文件 修改新脚本文件,内容参考如下: \[root@svr5 ~\]\# vim getupwd-awk.sh \#/bin/bash \#\# 创建空文件 > /tmp/getupwd.log \#\# 提取用户名列表 awk -F: '/:\\/bin\\/bash$/\{print $1\}' /etc/passwd > /tmp/users.tmp \#\# 通过for循环遍历用户名、查询密码记录,保存结果 for NAME in $(cat /tmp/users.tmp) do grep "^$NAME:" /etc/shadow | awk -F: '\{print $1" --> "$2 | \\ "cat >> /tmp/getupwd.log"\}' /etc/shadow done echo "用户分析完毕,请查阅文件 /tmp/getupwd.log" \#\# 完成后提示 \[root@svr5 ~\]\# chmod +x getupwd-awk.sh 步骤三:验证、测试脚本 \[root@svr5 ~\]\# ./getupwd-awk.sh 用户分析完毕,请查阅文件 /tmp/getupwd.log \[root@svr5 ~\]\# head -5 /tmp/getupwd.log root --> $6$IWgMYmRACwdbfwBo$dr8Yn983nswiJVw0dTMjzbDvSLeCd1GMYjbvsDiFEkL8jnXOLcocBQypOCr4C6BRxNowIxjh6U2qeFU0u1LST/ zengye --> $6$Qb37LOdzRl5995PI$L0zTOgnhGz8ihWkW81J.5XhPp/l7x2./Me2ag0S8tRndCBL9nIjHIKkUKulHxJ6TXyHYmffbVgUT6pbSwf8O71 clamav --> !! mysql --> !! abc --> !! .. .. ## **4 案例4:awk流程控制** ## ### **4.1 问题** ### 本案例要求了解awk的流程控制操作,可自行设置awk语句来有验证以下操作: if分支结构(双分支、多分支) while循环结构 break、continue等其他控制语句 ### **4.2 步骤** ### 实现此案例需要按照如下步骤进行。 步骤一:awk过滤中的if分支结构 1)单分支 统计/etc/passwd文件中UID小于或等于500的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0\}\{if($3<=500)\{i++\}\}END\{print i\}' /etc/passwd 39 统计/etc/passwd文件中UID大于500的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0\}\{if($3>500)\{i++\}\}END\{print i\}' /etc/passwd 28 统计/etc/passwd文件中登录Shell是“/bin/bash”的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0\}\{if($7~/bash$/)\{i++\}\}END\{print i\}'\\ /etc/passwd 29 统计/etc/passwd文件中登录Shell不是“/bin/bash”的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0\}\{if($7!~/bash$/)\{i++\}\}END\{print i\}'\\ /etc/passwd 38 2)双分支 分别统计/etc/passwd文件中UID小于或等于500、UID大于500的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0;j=0\}\{if($3<=500)\{i++\}else\{j++\}\}END\{print i,j\}' /etc/passwd 39 28 分别统计/etc/passwd文件中登录Shell是“/bin/bash”、 登录Shell不是“/bin/bash”的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0;j=0\}\{if($7~/bash$/)\{i++\}else\{j++\}\}\\ END\{print i,j\}' /etc/passwd 29 38 3)多分支 分别统计/etc/passwd文件中登录Shell是“/bin/bash”、“/sbin/nologin”、其他的用户个数: \[root@svr5 ~\]\# awk -F: 'BEGIN\{i=0;j=0;k=0\}\{if($7~/bash$/)\{i++\}\\ else if($7~/nologin$/)\{j++\}else\{k++\}\}END\{print i,j,k\}' /etc/passwd 29 33 5 步骤二:awk过滤中的while循环结构 1)while循环 统计/etc/passwd文件内“root”出现的次数。 —— 分析:以“:”或“/”做分隔,针对每一行的每一列进行比对,如果包含“root”,则次数加1。其中,逐行处理直接由awk完成,逐列处理交给while循环,通过i变量依次取$1、$2、……、$NF进行检查;变量j在预处理时赋值0,没匹配一个字段加1。 \[root@svr5 ~\]\# awk -F \[:/\] \\ 'BEGIN\{j=0\}\\ \{i=1\}\{while(i<=NF)\{if($i~/root/)\{j++\};i++\}\}\\ END\{print j\}' /etc/passwd 4 此例仅为说明while循环的用法。 实际应用时,上述操作可以简单处理,可通过命令替换将文件内容赋值给一个变量(变为一行文本),然后针对此变量值以目标字符串“root”作为分隔,获取总字段数-1即可得目标字符串的总数量: \[root@svr5 ~\]\# echo $(cat /etc/passwd) | awk -F "root" '\{print NF-1\}' 4 ## **5 案例5:awk扩展应用** ## ### **5.1 问题** ### 本案例要求使用awk工具完成下列两个任务: 分析Web日志的访问量排名,要求获得客户机的地址、访问次数,并且按照访问次数排名 ### **5.2 方案** ### 1)awk统计Web访问排名 在分析Web日志文件时,每条访问记录的第一列就是客户机的IP地址,其中会有很多重复的IP地址。因此只用awk提取出这一列是不够的,还需要统计重复记录的数量并且进行排序。 通过awk提取信息时,利用IP地址作为数组下标,每遇到一个重复值就将此数组元素递增1,最终就获得了这个IP地址出现的次数。 针对文本排序输出可以采用sort命令,相关的常见选项为-r、-n、-k。其中-n表示按数字顺序升序排列,而-r表示反序,-k可以指定按第几个字段来排序。 ### **5.3 步骤** ### 实现此案例需要按照如下步骤进行。 步骤一:统计Web访问量排名 分步测试、验证效果如下所述。 1)提取IP地址及访问量 \[root@svr5 ~\]\# awk '\{ip\[$1\]++\} END\{for(i in ip) \{print i,ip\[i\]\}\}' /var/log/httpd/access\_log 127.0.0.1 4 192.168.4.5 17 192.168.4.110 13 .. .. 2)对第1)步的结果根据访问量排名 \[root@svr5 ~\]\# awk '\{ip\[$1\]++\} END\{for(i in ip) \{print i,ip\[i\]\}\}' /var/log/httpd/access\_log | sort -nr -k 2 192.168.4.5 17 192.168.4.110 13 127.0.0.1 4 .. ..
还没有评论,来说两句吧...