• awk基本用法


    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;内存剩余容量freecpu负载uptime(最近1515分钟负载,相当于top的第一行)linux允许超负载);网卡流量ifconfigRX 发送包,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                                      (  tab)

    awk  -F  ‘BEGIN{print  “用户名 UID shell”}    /bash$/{print  $1” ”$3” ”$7;x++}  END{print  “总共用户量:”,x}’    /etc/passwd    

         

           awk -F: 'BEGIN{print "User UID Home"} {print $1" "$3" "$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文件内以127192开头的记录

    # 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

    #######################################

    awkif语句

    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小于或等于500UID大于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

    #######################################

    awkwhile循环

    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提取文本 

    案例2awk处理条件 

    案例3awk综合脚本应用 

    案例4awk流程控制 

    案例5awk扩展应用 

    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      //输出文件的第12

    #!/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}'      //输出第1312字段

    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过滤语句

    输出信息时,可以使用“ ”显示Tab制表位:

    [root@svr5 ~]# awk -F: 'BEGIN{print "User UID Home"}

    {print $1" "$3" "$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文件内以127192开头的记录

    列出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循环结构

    breakcontinue等其他控制语句

    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

    .. ..

     

  • 相关阅读:
    2017北京网络赛 J Pangu and Stones 区间DP(石子归并)
    2017北京网络赛 F Secret Poems 蛇形回路输出
    2017 北京网络赛 E Cats and Fish
    CF 1198 A. MP3 模拟+滑动窗口
    博弈论
    gym 101911
    容器STL
    POJ 3281 Dining 最大流+拆点
    hdu 1533 Going Home 最小费用最大流 (模板题)
    C#博文搜集
  • 原文地址:https://www.cnblogs.com/fuzhongfaya/p/8952530.html
Copyright © 2020-2023  润新知