命令格式
- 格式1: 前置命令 | awk [选项] '[匹配规则]{指令}'
- 格式2: awk [选项] '[匹配规则]{指令}' filename
| 选项 | 含义 |
|---|---|
| -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。
#配置记录(整行)
awk '/^kaikai/' /etc/passwd
awk '$0 ~ /^kaikai/' /etc/passwd
正则表达式
/正则内容/
~匹配,!~不匹配
数值/字符串比较
==,!=,>=,<=,>,<等
逻辑比较
&&逻辑与:期望多条件都成立
||逻辑或:只要有一个条件成立即满足要求
运算符
-,+,*,/,%,++,--,+=,-=,*=,/=
BEGIN{} {} END{}
行处理前 行处理 行处理后
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中,覆盖原来的内容,然后新的字符串分隔字段并进行处理,该过程将持续到所有行处理完毕。
| 变量 | 描述 |
|---|---|
| $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) |
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格式的指示符都以%开头,后跟一个字符;如下:
修饰符:
awk -F: '{printf "%-15s %-10s %-15\n",$1,$2,$3 }' /etc/passwd
#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
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中的所有字母转为大写
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
和 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
awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwdsz
awk -F: '{user[++i]=$1} END{(for (i in user) {print i,username[i]}}' /etc/passwdsz
awk -F: '{shell[$NF]++} END{for(i in shells){print i,shells[i]}}' /etc/passwd
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]}}
#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
某一天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
方法一 在双引号使用
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