• Shell-07Shell三剑客之awk


    命令格式

    命令格式
    - 格式1: 前置命令 | awk [选项] '[匹配规则]{指令}'
    - 格式2: awk [选项] '[匹配规则]{指令}' filename
    
    • 1
    • 2
    • 3

    awk选项

    选项含义
    -F fs指定以 fs 作为输入行的分隔符,awk 命令默认分隔符为空格或制表符。 如-F:
    -f file从脚本文件中读取 awk 脚本指令,以取代直接在命令行中输入指令。
    -v var=val在执行处理过程之前,设置一个变量 var,并给其设备初始值为 val。

    匹配规则

    • 这里的匹配规则,和 sed 命令中的 address 部分作用相同,用来指定脚本命令可以作用到文本内容中的具体行,可以使用字符串(比如 /test/,表示查看含有 test 字符串的行)或者正则表达式指定。另外需要注意的是,整个脚本命令是用单引号(‘’)括起,而其中的执行命令部分需要用大括号({})括起来。

    • 在 awk 程序执行时,如果没有指定执行命令,则默认会把匹配的行输出;如果不指定匹配规则,则默认匹配文本中所有的行。

    [root@localhost ~]# awk '/^$/ {print "Blank line"}' test.txt
    在此命令中,/^$/ 是一个正则表达式,功能是匹配文本中的空白行,同时可以看到,执行命令使用的是 print 命令,此命令经常会使用,它的作用很简单,就是将指定的文本进行输出。因此,整个命令的功能是,如果 test.txt 有 N 个空白行,那么执行此命令会输出 N 个 Blank line。
    
    • 1
    • 2
    #配置记录(整行)
    awk '/^kaikai/' /etc/passwd
    awk '$0 ~ /^kaikai/' /etc/passwd
    正则表达式
    	/正则内容/
    	~匹配,!~不匹配
    数值/字符串比较
    	==,!=,>=,<=,>,<等
    逻辑比较
    	&&逻辑与:期望多条件都成立
    	||逻辑或:只要有一个条件成立即满足要求
    运算符
    	-,+,*,/,%,++,--,+=,-=,*=,/=
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    指令

    BEGIN{} {} END{}

    行处理前 行处理 行处理后

    awk工作原理

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

    awk内部变量

    变量描述
    $n当前记录的第n个字段,字段间由FS分隔
    $0完整的输入记录
    ARGC命令行参数的数目
    ARGIND命令行中当前文件的位置(从0开始算)
    ARGV包含命令行参数的数组
    CONVFMT数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
    ERRNO最后一个系统错误的描述
    FIELDWIDTHS字段宽度列表(用空格键分隔)
    FILENAME当前文件名
    FNR各文件分别计数的行号
    FS字段分隔符(默认是任何空格)
    IGNORECASE如果为真,则进行忽略大小写的匹配
    NF一条记录的字段的数目
    NR已经读出的记录数,就是行号,从1开始
    OFMT数字的输出格式(默认值是%.6g)
    OFS输出记录分隔符(输出换行符),输出时用指定的符号代替换行符
    ORS输出记录分隔符(默认值是一个换行符)
    RLENGTH由match函数所匹配的字符串的长度
    RS记录分隔符(默认是一个换行符)
    RSTART由match函数所匹配的字符串的第一个位置
    SUBSEP数组下标分隔符(默认值是/034)

    awk操作

    print的使用格式

    print item1, item2, ...
    要点:
    1、各项目之间使用逗号隔开,而输出时则以空白字符分隔;
    2、输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
    3、print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print “”;

    格式化输出

    printf命令的使用格式:
    printf format, item1, item2, ...

    要点:
    1、其与print命令的最大不同是,printf需要指定format;
    2、format用于指定后面的每个item的输出格式;
    3、printf语句不会自动打印换行符;\n

    format格式的指示符都以%开头,后跟一个字符;如下:

    • %c: 显示字符的ASCII码;
    • %d, %i:十进制整数;
    • %e, %E:科学计数法显示数值;
    • %f: 显示浮点数;
    • %g, %G: 以科学计数法的格式或浮点数的格式显示数值;
    • %s: 显示字符串;
    • %u: 无符号整数;
    • %%: 显示%自身;

    修饰符:

    • N: 显示宽度;
    • -: 左对齐;
    • +:显示数值符号;
    awk -F: '{printf "%-15s %-10s %-15\n",$1,$2,$3 }' /etc/passwd
    
    • 1

    awk控制语句

    #if-else
    语法:if (condition) {then-body} else {[ else-body ]}
    例子:
    awk -F: '{if ($1=="root") print $1, "Admin"; else print $1, "Common User"}' /etc/passwd
    
    
    #while
    语法: while (condition){statement1; statment2; ...}
    awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd
    
    
    #do-while
    语法: do {statement1, statement2, ...} while (condition)
    awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd
    
    #for
    语法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
    awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd
    
    #case
    语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
    
    #break 和 continue
    常用于循环或case语句中
    
    #next
    提前结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户:
    # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    awk的内置函数

    split(string, array [, fieldsep [, seps ] ])
    功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列;
    
    netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
    
    length([string])
    功能:返回string字符串中字符的个数;
    
    
    substr(string, start [, length])
    功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
    
    system(command)
    功能:执行系统command并将结果返回至awk命令
    
    systime()
    功能:取系统当前时间
    
    tolower(s)
    功能:将s中的所有字母转为小写
    
    toupper(s)
    功能:将s中的所有字母转为大写
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    BEGIN 关键字

    awk 中还可以指定脚本命令的运行时机。默认情况下,awk 会从输入中读取一行文本,然后针对该行的数据执行程序脚本,但有时可能需要在处理数据前运行一些脚本命令,这就需要使用 
    BEGIN 会强制 awk 在读取数据前执行该关键字后指定的脚本命令,例如:
    [root@localhost ~]# cat data.txt
    Line 1
    Line 2
    Line 3
    [root@localhost ~]# awk 'BEGIN {print "The data File Contents:"} {print $0}' data.txt
    The data File Contents:
    Line 1
    Line 2
    Line 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    END关键字

    和 BEGIN 关键字相对应,END 关键字允许我们指定一些脚本命令,awk 会在读完数据后执行
    [root@localhost ~]# awk 'BEGIN {print "The data File Contents:"} {print $0} END {print "End of File"}' data.txt
    The data File Contents:
    Line 1
    Line 2
    Line 3
    End of File
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例

    数组

    awk -F: '{username[++i]=$1}  END{print username[1]}' /etc/passwdsz
    
    • 1

    数组遍历

    awk -F: '{user[++i]=$1}  END{(for  (i in user)   {print i,username[i]}}' /etc/passwdsz
    
    • 1

    统计 /etc/passwd的的shell的数量

    awk -F: '{shell[$NF]++} END{for(i in shells){print i,shells[i]}}' /etc/passwd
    
    • 1

    网站访问状态统计

    netstat -ant | grep ':80' | awk'{status[$NF++]} END{for(i in status){print i,status[i]}}
    ss -an | grep ':80' | awk'{status[$2++]} END{for(i in status){print i,status[i]}}
    
    • 1
    • 2

    统计当前访问的每个IP的数量

    #ss -an | grep ':80' | awk -F":" '!/LISTEN/{ips[$(N-1)F++]} END{for(i in ips){print i,status[i]}} | sort -k2 -rn  | head -5
    
    • 1

    统计Apace/Nginx的Pv量

    某一天PV量
    gerp '07/Aug/2020' access.log | wc -l
    不同IP的访问量
    awk  '/07\/Aug\/2020/{ips[$1]++} END{for(i in shells){print i,ips[i]}}' access.log
    
    • 1
    • 2
    • 3
    • 4

    awk使用外部变量的方法

    方法一  在双引号使用
    var = "test"
    echo "unix scrip" | awk "gsub(/unix/,\"$var\")"
    方法二  在单引号使用
    var = "test"
    echo "unix scrip" | awk 'gsub(/unix/,"'"$var"'")'
    
    awk -v user=root -F:'$1 == user' /etc/passwd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    多肽标签VSV-G Tag、YTDIEMNRLGK
    商场购物中心私域运营 百货公司会员小程序积分商城
    spring-cloud-alibaba - nacos配置中心&注册中心 实战
    算法系列文章(一)———打印菱形
    flutter plugins插件【二】【FlutterAssetsGenerator】
    XML快速入门
    怎样通过 Etherscan 验证智能合约
    Unity 单例-接口模式
    10-Dubbo架构设计与底层原理-集群容错之 Router
    SpringBoot | Spring Boot“整合Redis“
  • 原文地址:https://blog.csdn.net/a13554371686/article/details/126899167