目录
AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。
之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
awk命令的完整语法
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
[-F|-f|-v] 大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
' ' 引用代码块
BEGIN 初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
// 匹配代码块,可以是字符串或正则表达式
{} 命令代码块,包含一条或多条命令
; 多条命令使用分号分隔
END 结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
awk的命令的执行过程
- 1、通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 {} 的内容。
- 2、完成 BEGIN 块的执行,开始执行body块。
- 3、读入有 \n 换行符分割的记录。
- 4、将记录按指定的域分隔符划分域,填充域,$0 则表示所有域(即一行内容),$1 表示第一个域,$n 表示第 n 个域。
- 5、依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。
- 6、循环读取并执行各行直到文件结束,完成body块执行。
- 7、开始 END 块执行,END 块可以输出最终结果。
选项
- -F fs or --field-separator fs
指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。 - -v var=value or --asign var=value
赋值一个用户定义变量。 - -f scripfile or --file scriptfile
从脚本文件中读取awk命令。 - -mf nnn and -mr nnn
对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。 - -W compact or --compat, -W traditional or --traditional
在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。 - -W copyleft or --copyleft, -W copyright or --copyright
打印简短的版权信息。 - -W help or --help, -W usage or --usage
打印全部awk选项和每个选项的简短说明。 - -W lint or --lint
打印不能向传统unix平台移植的结构的警告。 - -W lint-old or --lint-old
打印关于不能向传统unix平台移植的结构的警告。 - -W posix
打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。 - -W re-interval or --re-inerval
允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。 - -W source program-text or --source program-text
使用program-text作为源代码,可与-f命令混用。 - -W version or --version
打印bug报告信息的版本。
awk支持的运算符
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
|| | 逻辑或 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式(模糊匹配) |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
in | 数组成员 |
==和!= | 精准匹配和精准不匹配 |
常用内建变量
变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,字段间由FS分隔 |
$0 | 完整的输入记录 |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
FS | 字段分隔符(默认是任何空格),BEGIN命令时使用 |
NF | 一条记录的字段的数目 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFS | 输出字段分隔符,默认值为任何空格 |
ORS | 输出记录分隔符(默认值是一个换行符)即文本是按一行一行输出 |
RS | 记录分隔符(默认是一个换行符)即文本是按一行一行输入 |
IGNORECASE | 如果为真,则进行忽略大小写的匹配 |
+ 匹配时表示1个或1个以上
/[0-9][0-9]+/ 两个或两个以上数字
/[0-9][0-9]*/ 一个或一个以上数字
注意:
-F'[:#/]' 定义三个分隔符
-F指定分隔符时,-F与指定的分隔符之间加不加空格都行
print & $0
print 是awk打印指定内容的主要命令
1.输出/etc/passwd文件中所有的内容
awk '{print}' /etc/passwd
awk '{print $0}' /etc/passwd
awk '/li/' /etc/passwd #默认命令即为输出匹配的整行
2.不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本
awk '{print " "}' /etc/passwd
3.输出相同个数的a行,一行只有一个a字母
awk '{print "a"}' /etc/passwd
4.将每一行的前二个字段,分行输出,进一步理解一行一行处理文本
awk -F: '{print $1; print $2}' /etc/passwd
5.输出字段1,3,6,以制表符作为分隔符统计一个文件中的空行
awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd
6.统计test.txt文件中的空行数量
awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test.txt
7.统计当前文件夹下所有文件和文件夹大小的和,即当前文件夹的大小
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'
8.使用正则,字符串匹配,输出第二列包含 "th",并打印第二列与第四列
awk '$2 ~ /th/ {print $2,$4}' log.txt
~ 表示模式开始。// 中是模式
忽略大小写
awk 'BEGIN{IGNORECASE=1} /this/' log.txt
模式取反
awk -F: '$1 !/li/ {print $2,$4}' /etc/passwd
awk -F: '$1 !~ /li/ {print $2,$4}' /etc/passwd
awk脚本
关于 awk 脚本,我们需要注意两个关键词 BEGIN 和 END。
- BEGIN{ 这里面放的是执行前的语句 }
- END {这里面放的是处理完所有的行后要执行的语句 }
- {这里面放的是处理每一行时要执行的语句}
假设有这么一个文件(学生成绩表):
$ cat score.txt
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
我们的 awk 脚本如下:
$ cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
我们来看一下执行结果:
$ awk -f cal.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
-F指定分隔符
awk默认分隔符为任意空格,将一行文本分割成多个字段
awk -F":" '{print $1}' /etc/passwd
#//$1与$3相连输出,不分隔
awk -F":" '{print $1 $3}' /etc/passwd
#//多了一个逗号,$1与$3使用空格分隔
awk -F":" '{print $1,$3}' /etc/passwd
#//$1与$3之间手动添加空格分隔
awk -F":" '{print $1 " " $3}' /etc/passwd
#//自定义输出
awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd
#//显示每行有多少字段
awk -F: '{print NF}' /etc/passwd
#//将每行第NF个字段的值打印出来
awk -F: '{print $NF}' /etc/passwd
#//显示只有4个字段的行
awk -F: 'NF==4 {print }' /etc/passwd
#//显示每行字段数量大于2的行
awk -F: 'NF>2{print $0}' /etc/passwd
#//输出每行的行号
awk '{print NR,$0}' /etc/passwd
#//依次打印行号,字段数,最后字段值,制表符,每行内容
awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd
#//显示第5行
awk -F: 'NR==5{print}' /etc/passwd
#//显示第5行和第6行
awk -F: 'NR==5 || NR==6{print}' /etc/passwd
#//不显示第一行
route -n|awk 'NR!=1{print}'
//匹配代码块
//纯字符匹配 !//纯字符不匹配 ~//字段值匹配 !~//字段值不匹配 ~/a1|a2/字段值匹配a1或a2
awk '/mysql/' /etc/passwd
awk '/mysql/{print }' /etc/passwd
awk '/mysql/{print $0}' /etc/passwd //三条指令结果一样
awk '!/mysql/{print $0}' /etc/passwd //输出不匹配mysql的行
awk '/mysql|mail/{print}' /etc/passwd
awk '!/mysql|mail/{print}' /etc/passwd
awk -F: '/mail/,/mysql/{print}' /etc/passwd //区间匹配
#//匹配包含27为数字开头的行,如27,277,2777...
awk '/[2][7][7]*/{print $0}' /etc/passwd
awk -F: '$1~/mail/{print $1}' /etc/passwd //$1匹配指定内容才显示
awk -F: '{if($1~/mail/) print $1}' /etc/passwd //与上面相同
awk -F: '$1!~/mail/{print $1}' /etc/passwd //不匹配
awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwd
IF语句
必须用在{}中,且比较内容用()扩起来
awk -F: '{if($1~/mail/) print $1}' /etc/passwd //简写
awk -F: '{if($1~/mail/) {print $1}}' /etc/passwd //全写
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd //if...else...
AWK 数组
AWK 可以使用关联数组这种数据结构,索引可以是数字或字符串。
AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。
数组使用的语法格式:
array_name[index]=value
- array_name:数组的名称
- index:数组索引
- value:数组中元素所赋予的值
.csv文件:以,作为字段分隔符,在Windows中可以直接用excel打开
练习
1.只显示df -h结果的第一列文件系统
df -h | awk '{print $1}'
2.显示passwd文件的第5行和第10行的行号和用户名
awk -F: 'NR==10 || NR==5{print NR,$1}' /etc/passwd
3.使用NF变量显示passwd文件倒数第二列的内容
awk -F: '{print NR,$(NF-1)}' /etc/passwd
4.显示passwd文件中第5到第10行的用户名
awk -F: 'NR==10 || NR==5{print $1}' /etc/passwd
5.显示passwd文件中第7列不是bash的用户名
awk -F: '$7 !="/bin/bash"{print $7}' /etc/passwd
6.显示passwd文件中行号是5结尾的行号和整行内容
cat /etc/passwd | awk 'NR~/5$/{print NR,$0}'
7.用ifconfig/ip add 只显示ip
yum install net-tools -y -->安装ifconfig命令的软件
ifconfig | awk 'NR==2{print $2}'
ip add |awk '/inet.*ens[0-9]+$/{split($2,a,"/");print a[1]}'
8.ifconfig 命令后使用awk显示ens33的入站流量和出站流量(字节)
ifconfig | awk 'NR==5 ||NR==7{print $5}'
#观察流量每两秒的变化
watch -n 2 -d "ifconfig |awk 'NR==5{print $5}'"
9.使用awk命令统计以r开头的用户名和用户数目
cat /etc/passwd | awk -F: 'BEGIN{i=0}/^r/{i++;print $1}END{print i}'