• Shell脚本文本三剑客之awk编辑器


    目录

    一、awk简介

    二、awk工作原理

    三、awk命令格式 

    四、awk命令的使用

    1.print操作按行输出文本

    2.print操作按字段截取输出文本

    3.使用BEGIN和END指定操作

    4.使用管道符号,双引号调用shell命令

    5.使用操作getline 

    6.使用操作OFS 

    7.配合数组使用


    一、awk简介

            awk是linux的一个强大的命令,具备强大的文本格式化能力,比如对一堆看起来没有什么规律的日志文件,文本文件等,通过awk命令格式化输出为专业的可以做为应用级数据分析的样式。

    二、awk工作原理

            逐行读取文本,默认以空格制表符为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

            sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”,然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。

            在使用awk命令的过程中,可以使用逻辑操作符"&&"表示"与"、"||"表示"或"、"!"表示"非",还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方

    三、awk命令格式 

    awk [选项] '模式或条件 {操作表达式}' 文件名...

    awk常用选项

    选项作用

    -F

    后面跟符号,指定列分隔符
    -v后面跟变量,允许使用变量

    awk常见内建变量

    内建变量作用
    FS

    列分隔符,指定每行文本的字段分隔符(默认为空格和制表符)。

    与-F 选项作用相同

    OFS  输出内容的列分隔符
    NF

    当前处理行的字段个数

    $NF可以表示最后一行

    NR指定当前处理的行的行号
    $0当前处理的行的整行内容
    $n当前处理行的第n个字段
    RS行分隔符,指定航分隔符(默认是换行符"\n")

    四、awk命令的使用

    1.print操作按行输出文本

    1. //1.输出所有内容
    2. [root@localhost1 ~]#awk '{print}' numfile
    3. one
    4. two
    5. three
    6. four
    7. five
    8. six
    9. seven
    10. eight
    11. nine
    12. ten
    13. [root@localhost1 ~]#awk '{print $0}' numfile #$0代表匹配到的整行
    14. one
    15. two
    16. three
    17. four
    18. five
    19. six
    20. seven
    21. eight
    22. nine
    23. ten
    24. //2.指定行,输出1~3行内容
    25. [root@localhost1 ~]#awk 'NR==1,NR==3 {print}' numfile
    26. one
    27. two
    28. three
    29. [root@localhost1 ~]#awk '(NR>=1)&&(NR<=3) {print}' numfile
    30. one
    31. two
    32. three
    33. //3.指定的几行,输出第1、3行
    34. [root@localhost1 ~]#awk 'NR==1||NR==3 {print}' numfile
    35. one
    36. three
    37. //4.输出奇偶行
    38. [root@localhost1 ~]#awk '(NR%2)==0 {print}' numfile
    39. two
    40. four
    41. six
    42. eight
    43. ten
    44. [root@localhost1 ~]#awk '(NR%2)==1 {print}' numfile
    45. one
    46. three
    47. five
    48. seven
    49. nine
    50. //5.输出行号
    51. [root@localhost1 ~]#awk '{print NR,$0}' file1
    52. 1 one two three
    53. 2 four five six
    54. 3 seven eight nine
    55. 4 ten eleven twelve
    56. //6.指定第1行包含o的行。输出行号和内容
    57. [root@localhost1 ~]#awk '$1~"o" {print NR,$0}' file1
    58. 1 one two three
    59. 2 four five six
    60. //7.指定输出包含指定字符串的行
    61. [root@localhost1 ~]#awk '/root/ {print}' /etc/passwd
    62. root:x:0:0:root:/root:/bin/bash
    63. operator:x:11:0:operator:/root:/sbin/nologin
    64. //8.指定输出包含指定正则表达式的行
    65. [root@localhost1 ~]#awk '/^root.*bash$/ {print}' /etc/passwd
    66. root:x:0:0:root:/root:/bin/bash

    2.print操作按字段截取输出文本

    1. //1.指定字段分隔符":",输出每行1,3字段
    2. [root@localhost1 ~]#awk -F ':' '{print $1,$3}' /etc/passwd
    3. root 0
    4. bin 1
    5. daemon 2
    6. adm 3
    7. lp 4
    8. sync 5
    9. shutdown 6
    10. halt 7
    11. mail 8
    12. ...
    13. avahi 70
    14. postfix 89
    15. tcpdump 72
    16. hx 1000
    17. apache 48
    18. zhangsan 1001
    19. lisi 1002
    20. zhaoliu 1003
    21. wangwu 1004
    22. qianqi 1005
    23. zhuba 1006
    24. //2.在第1条基础上,限定行范围,第3个字段值小于1000的行,输出每行1,3字段
    25. [root@localhost1 ~]#awk -F ':' '$3>1000 {print $1,$3}' /etc/passwd
    26. nfsnobody 65534
    27. zhangsan 1001
    28. lisi 1002
    29. zhaoliu 1003
    30. wangwu 1004
    31. qianqi 1005
    32. zhuba 1006
    33. //3.指定最后一个字段包含sbin的行,输出第1和最后一个字段
    34. [root@localhost1 ~]#awk -F ':' '$NF~"sbin" {print $1,$NF}' /etc/passwd
    35. bin /sbin/nologin
    36. daemon /sbin/nologin
    37. adm /sbin/nologin
    38. lp /sbin/nologin
    39. shutdown /sbin/shutdown
    40. halt /sbin/halt
    41. mail /sbin/nologin
    42. operator /sbin/nologin
    43. games /sbin/nologin
    44. ...
    45. rpcuser /sbin/nologin
    46. nfsnobody /sbin/nologin
    47. gnome-initial-setup /sbin/nologin
    48. sshd /sbin/nologin
    49. avahi /sbin/nologin
    50. postfix /sbin/nologin
    51. tcpdump /sbin/nologin
    52. apache /sbin/nologin
    53. named /sbin/nologin
    54. dhcpd /sbin/nologin
    55. //4.输出最后一个字段既不是/sbin/nologin也不是/bin/bash的行
    56. [root@localhost1 ~]#awk -F ':' '($NF!="/sbin/nologin")&&($NF!="/bin/bash") {print $1,$NF}' /etc/passwd
    57. sync /bin/sync
    58. shutdown /sbin/shutdown
    59. halt /sbin/halt

    3.使用BEGIN和END指定操作

    awk [选项] 'BEGIN {表达式}; [条件] {操作表达式}; END {表达式}' 文件名... 

    • BEGIN {操作1}       awk在读取文件之前执行的操作
    • [条件] {操作2}         awk 逐行读取文件时执行的操作
    • END {操作3}           awk在处理完文件所有行之后执行的操作
    1. //1.输出结尾为nologin的行,并为每行计数显示行号,最后输出总行数
    2. [root@localhost1 ~]#awk 'BEGIN {a=0}; /nologin$/ {a++; print a,$0}; END {print " 共有"a"行"}' /\etc/passwd
    3. 1 bin:x:1:1:bin:/bin:/sbin/nologin
    4. 2 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    5. 3 adm:x:3:4:adm:/var/adm:/sbin/nologin
    6. 4 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    7. 5 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    8. ...
    9. 34 nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
    10. 35 gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
    11. 36 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    12. 37 avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
    13. 38 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    14. 39 tcpdump:x:72:72::/:/sbin/nologin
    15. 40 apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
    16. 41 named:x:25:25:Named:/var/named:/sbin/nologin
    17. 42 dhcpd:x:177:177:DHCP server:/:/sbin/nologin
    18. 共有42

    4.使用管道符号,双引号调用shell命令

    1. //1.输出以:分割的第1和3个字段
    2. [root@localhost1 ~]#echo $PATH |awk 'BEGIN {FS=":"}; {print $1,$3}'
    3. /usr/local/sbin /usr/sbin
    4. //2.输出$PATH的每个文件
    5. [root@localhost1 ~]#echo $PATH |awk 'BEGIN {RS=":"}; {print NR,$0} END {print "共有"NR"行"}'
    6. 1 /usr/local/sbin
    7. 2 /usr/local/bin
    8. 3 /usr/sbin
    9. 4 /usr/bin
    10. 5 /root/bin
    11. 共有5
    12. //3.输出ens33网卡的ip和mac地址
    13. [root@localhost1 ~]#ifconfig ens33
    14. ens33: flags=4163 mtu 1500
    15. inet 192.168.116.10 netmask 255.255.255.0 broadcast 192.168.116.255
    16. inet6 fe80::7791:1d06:d2da:af8e prefixlen 64 scopeid 0x20
    17. ether 00:0c:29:3b:4b:c3 txqueuelen 1000 (Ethernet)
    18. RX packets 19934 bytes 1547296 (1.4 MiB)
    19. RX errors 0 dropped 0 overruns 0 frame 0
    20. TX packets 8225 bytes 867536 (847.2 KiB)
    21. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    22. [root@localhost1 ~]#ifconfig ens33 |awk 'NR==2 {print $2}'
    23. 192.168.116.10
    24. [root@localhost1 ~]#ifconfig ens33 |awk '/ether/ {print $2}'
    25. 00:0c:29:3b:4b:c3
    26. //4.内存占用多少MB
    27. [root@localhost1 ~]#free -m
    28. total used free shared buff/cache available
    29. Mem: 1819 563 849 14 406 1080
    30. Swap: 8191 0 8191
    31. [root@localhost1 ~]#free -m | awk 'NR==2 {print $3}'
    32. 563
    33. [root@localhost1 ~]#free -m | awk '/Mem/ {print $3}'
    34. 563
    35. //5.内存占用率
    36. [root@localhost1 ~]#free -m
    37. total used free shared buff/cache available
    38. Mem: 1819 563 848 14 406 1080
    39. Swap: 8191 0 8191
    40. [root@localhost1 ~]#free -m | awk '/Mem/ {print ($4/$2*100)"%"}'
    41. 46.619%
    42. [root@localhost1 ~]#free -m | awk '/Mem/ {print int($4/$2*100)"%"}'
    43. 46%
    44. //6.CPU空闲率
    45. [root@localhost1 ~]#top -b -n1 |awk -F "," '/Cpu/ {print $4}' |awk '{print $1"%"}'
    46. 98.5%
    47. //7.计算开机时间
    48. [root@localhost1 ~]#date -d "$(awk '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"
    49. 20220905 21:28:50
    50. [root@localhost1 ~]#date -d "-$(awk '{print $1}' /proc/uptime) second" +"%Y%m%d %H:%M:%S"
    51. 20220907 08:32:41

    5.使用操作getline 

    • 当getline左右无重定向符“<”或“|”时,awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF,NR,FNR和$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。
    • 当getline左右有重定向符“<”或“|”时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。
       
    1. //1.利用getline输出奇偶行
    2. [root@localhost1 ~]#seq 10 |awk '{getline;print $0}'
    3. 2
    4. 4
    5. 6
    6. 8
    7. 10
    8. [root@localhost1 ~]#seq 10 |awk '{print $0;getline}'
    9. 1
    10. 3
    11. 5
    12. 7
    13. 9
    14. //2.利用getline输出主机名
    15. [root@localhost1 ~]#awk 'BEGIN {"hostname" |getline ;{print $0} }'
    16. localhost1
    17. //3.利用getline读取w命令显示的行数,统计出在线用户数(减去前2个无关行)
    18. [root@localhost1 ~]#w
    19. 14:56:47 up 6:24, 1 user, load average: 0.00, 0.01, 0.05
    20. USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
    21. root pts/0 192.168.116.1 14:17 7.00s 0.14s 0.02s w
    22. [root@localhost1 ~]#w |awk 'NR>2 {print $0 | "wc -l"}'
    23. 1

    6.使用操作OFS 

    1. //1.利用OFS输出第1和3个字段,并用:作为输出的分隔符
    2. [root@localhost1 ~]#echo "A B C D" |awk '{OFS=":";print $1,$3}'
    3. A:C
    4. //2.利用OFS指定分割符输出整行内容时,需要使用$1=$1刷新整行内容
    5. [root@localhost1 ~]#echo "A B C D" |awk '{OFS=":";$1=$1;print $0}'
    6. A:B:C:D

    7.配合数组使用

    1. //1.输出指定数组值
    2. [root@localhost1 ~]#awk 'BEGIN {a[0]=10;a[1]=20;print a[1]}'
    3. 20
    4. [root@localhost1 ~]#awk 'BEGIN {a[0]=10;a[1]=20;print a[0]}'
    5. 10
    6. //2.使用字符串作为数组索引,输出指定数组值
    7. [root@localhost1 ~]#awk 'BEGIN {a["abc"]=10;a["xyz"]=20;print a["abc"]}'
    8. 10
    9. //数组值也可以为字符串
    10. [root@localhost1 ~]#awk 'BEGIN {a["abc"]="aa";a["xyz"]="xx";print a["abc"]}'
    11. aa
    12. //3.遍历数组
    13. [root@localhost1 ~]#awk 'BEGIN {a[0]=10;a[1]=20;a[2]=30; for(i in a) {print i,a[i]}}' 0 10
    14. 1 20
    15. 2 30

    利用数组做统计

            awk 根据指定字段读取每行的字段内容,使用字段内容作为数组的索引,如果出现相同内容的行,则用这个行内容做的数组的值自增1;END{ for(i in arr) {print arr[i],i} awk 读取完所有行内容后,使用for循环遍历这个数组的下标,打印每个下标出现的次数和下标的值。

    awk '{arr{$n}++}; END{ for(i in arr) {print arr[i],i}' 文件名..

    1. //1.利用数组统计,输出文件中各行出现的次数并排序
    2. [root@localhost1 ~]#cat test.txt | awk '{arr[$1]++}; END{for(i in arr) {print arr[i],i}}' test.txt |sort -rn
    3. 4 aaa
    4. 3 bbb
    5. 1 ccc
    6. //2.利用数组统计,过滤输入密码超过3次的主机ip
    7. [root@localhost1 /]#awk '/Failed password/ {a[$13]++};END{for(i in arr) {print arr[i],i}}' /var/log/secure |awk '$1>3 {print $2}'
    8. 192.168.116.1
    9. 192.168.116.10

    利用数组做去重 

    awk '1' 就是 awk '1{print}' ,允许打印读入的行内容,例:echo 123 | awk '1'

    awk '0' 就是 awk '0{print}' ,不允许打印读入的行内容,例:echo 123 | awk '0' 

    var++ 的形式:先读取 var 变量值,再对 var 值 +1
    awk 处理第一行时:先读取 a[$1] 值再自增,a[$1] 即 a[1] 值为空(即0),即为 awk '!0',即为 awk '1',即为 awk'1{print}'
    awk 处理第二行时:先读取 a[$1] 值再自增,a[$1] 即 a[1] 值为 1,即为 awk '!1',即为 awk '0',即为 awk '0{print}' 

    1. //使用!arr[$1]++实现禁止重复读取到的内容输出
    2. [root@localhost1 ~]#arr=(1 2 3 4 3 4 5 3 5 2 3 1)
    3. [root@localhost1 ~]#echo ${arr[@]} |awk 'BEGIN{RS=" "}; !arr[$1]++'
    4. 1
    5. 2
    6. 3
    7. 4
    8. 5
  • 相关阅读:
    【andriod】设备APP开发之各种细节部署和操作
    D23-读论文D23&算法D23
    手把手教你安装VSCode(附带图解步骤)
    记一次前端CryptoJS AES解密
    牛客网解题之矩形覆盖
    greenhills compiler 2021.1.4 for x86 Linux
    用函数的方法通过冒泡法实现对一个数组(乱序)到有序排序(由大到小排序)
    专题三:穷举、暴搜、深搜、回溯、剪枝【递归、搜索、回溯】
    MindFusion.WinForms Pack 2022.R2
    国内最好的ai软件是哪个?探索国内顶尖AI软件的魅力与实力
  • 原文地址:https://blog.csdn.net/weixin_58544496/article/details/126717620