awk命令简介:
awk是一个强大的报告生成工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
一、awk主要用到的地方:
1、根据要求选择文件的某几行,几列或部分字段以供显示输出。
2、分析文档中的某一个字出现的频率、位置等。
3、根据某一个文档的信息准备格式化输出。
4、以一个功能十分强大的方式过滤输出文档。
5、根据文档中的数值进行计算。
二、语法:
# awk [options] 'script' file1 file2, ...
# awk [options] 'PATTERN { action }' file1 file2, ...
awk应用实例:
一、print
print的使用格式: print item1, item2, ...
例如、显示/etc/passwd里边用户的名字和ID号
[root@www ~]# awk -F: '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6
注:
1、各项目之间使用逗号隔开,而输出时则以空白字符分隔;
2、输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
3、print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print "";
二、awk的模式:
awk 'program' input-file1 input-file2 ... 其中的program为: pattern { action } pattern { action } ...
常见的模式类型:
1、Empty(空模式):则输出指定文件中的所有行
[root@www ~]# awk '{print $1,$3}' /etc/passwd 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
2、Regexp: 正则表达式,使用通配符的扩展集,格式为/regular expression/
例如:找出默认shell是bash的用户
[root@www ~]# awk -F: '/bash$/{print $1,$7}' /etc/passwd root /bin/bash mysql /bin/bash liming /bin/bash [root@www ~]#
3、expresssion: 表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和!~(不匹配)。
> | 大于 |
< | 小于 |
<= | 小于等于 |
>= | 大于等于 |
~ | 被模式匹配 |
!~ | 不被模式匹配 |
例:显示ID号大于等于50的用户
[root@www ~]# awk -F: '$3>=50{print $1,$3}' /etc/passwd nobody 99 dbus 81 usbmuxd 113 vcsa 69 rtkit 499 avahi-autoipd 170 pulse 498 haldaemon 68 saslauth 497 postfix 89 abrt 173 nfsnobody 65534 sshd 74 tcpdump 72 dhcpd 177 liming 500
例:显示默认shell为bash的用户
[root@www ~]# awk -F: '$7~/bash/{print $1,$7}' /etc/passwd root /bin/bash mysql /bin/bash liming /bin/bash [root@www ~]#
显示默认shell不是bash的用户
[root@www ~]# awk -F: '$7!~/bash/{print $1,$7}' /etc/passwd bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin sync /bin/sync shutdown /sbin/shutdown
4、BEGIN:特殊模式,仅在awk命令执行前运行一次
例如:
[root@www ~]# awk -F: 'BEGIN{print "Username ID"}{print $1,$3}' /etc/passwd Username ID //这样的话会在内容显示之前,给内容添加个表头 root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6
5、END:让用户在最后一条输入记录被读取之后发生的动作。
[root@www ~]# awk -F: 'BEGIN{print "Username ID"}{print $1,$3}END{print "=====END===="}' /etc/passwd Username ID root 0 bin 1 daemon 2 adm 3 lp 4 省略中间内容。。。。 sync 5 dhcpd 177 mysql 27 liming 500 =====END==== //明确指定以某个特定的符号结尾 [root@www ~]#
三、awk字段分隔符
FS: field separator,读取文件本时,所使用字段分隔符;
例:
[root@www ~]# awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 默认为空白,这里指定分隔符为冒号
OFS: Output Filed Separator: 指定输出分隔符
[
root@www ~]# awk 'BEGIN{FS=":";OFS="==="}{print $1,$3}' /etc/passwd root===0 bin===1 daemon===2 adm===3 lp===4 sync===5 shutdown===6
四、printf
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: 显示宽度;
-: 左对齐;
+:显示数值符号;
例子:显示当前用户的名字和ID号
[root@www ~]# awk -F: '{printf "%-15s %i\n",$1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6
五、输出重定向
print items > output-file print items >> output-file print items | command
特殊文件描述符:
/dev/stdin:标准输入 /dev/sdtout: 标准输出 /dev/stderr: 错误输出 /dev/fd/N: 某特定文件描述符,如/dev/stdin就相当于/dev/fd/0;
例子:
# awk -F: '{printf "%-15s %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd
六、awk的操作符:
6.1 算术操作符:
-x: 负值 +x: 转换为数值; x^y: x**y: 次方 x*y: 乘法 x/y:除法 x+y: x-y: x%y:
6.2 赋值操作符:
= += -= *= /= %= ^= **= ++ --
注:如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代;
6.3 布尔值
awk中,任何非0值或非空字符串都为真,反之就为假;
6.4 表达式间的逻辑关系符:
&& 与 两个条件必须同时满足
|| 或 两个条件满足其一即可
例:显示默认shell为bash且ID号大于等于50的用户
[root@www ~]# awk -F: '$3>=50 && $7~/bash/{printf "%-15s %i %s\n",$1,$3,$7}' /etc/passwd liming 500 /bin/bash [root@www ~]#
七、awk内置变量之数据变量:
NR: The number of input records,awk命令所处理的记录数;如果有多个文件,这个数目会把处理的多个文件中行统一计数;
NF:Number of Field,每一行拥有的总字段数
FNR: 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;
ARGV: 数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的参数的个数;
FILENAME: awk命令所处理的文件的名称;
ENVIRON:当前shell环境变量及其值的关联数组;
如:awk 'BEGIN{print ENVIRON["PATH"]}'
例:显示当前系统挂载的设备和挂载点
[root@www ~]# df -lh | awk '!/^File/{print $1,NF}' //引用变量NF /dev/mapper/vg0-root 6 tmpfs 6 /dev/sda1 6 /dev/mapper/vg0-usr 6 /dev/mapper/vg0-var 6 /dev/sr0 6 [root@www ~]# df -lh | awk '!/^File/{print $1,$NF}' //引用变量NF /dev/mapper/vg0-root / tmpfs /dev/shm /dev/sda1 /boot /dev/mapper/vg0-usr /usr /dev/mapper/vg0-var /var /dev/sr0 /media [root@www ~]#
注:在awk的使用中,引用变量本身的值不用加$,但是注意的是,不加的话显示的是一个数值,即将一行切片的第几片,加上$的话,则显示的是第几片的内容
2.3 用户自定义变量
-v 用于指定用户自定义变量
[root@www ~]# awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd 2 [root@www ~]#
八 控制语句:
8.1 if-else
语法:if (condition) {then-body} else {[ else-body ]}
例子:
当用户ID号为0的时候,就说他是管理员,否则就说是普通用户
[root@www ~]# awk -F: '{if ($3==0){printf "%-15s %s\n",$1, "Adminitrator;"} else{ printf "%-15s %s\n",$1, "Common User"}}' /etc/passwd root Adminitrator; bin Common User daemon Common User adm Common User lp Common User sync Common User shutdown Common User
统计当前系统上ID号大于等于500的用户的个数
[root@www ~]# awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd 2 [root@www ~]#
注:如果一个if-else语句的一个{}中只有一个语句,可以不用{},有多个则必须使用{},每个语句之间需要用分号隔开,控制语句本身必须要分号结束
8.2 while
语法: while (condition){statement1; statment2; ...}
显示每一个用户的前三段
[root@www ~]# awk -F: '{i=1;while (i<=3) {printf "%s ",$i;i++;};printf "\n"}' /etc/passwd root x 0 bin x 1 daemon x 2 adm x 3 lp x 4 sync x 5 shutdown x 6
显示该文件里边每一行大于等于500的数字
[root@www ~]# cat sum.txt 222 111 1231241235 3141 1321432546 53242 2131 1231 324 22 22 42 56 78 [root@www ~]# awk '{i=1;while (i<=NF) {if ($i>=500) print $i; i++}}' sum.txt 1231241235 3141 1321432546 53242 2131 1231 [root@www ~]#
注:如果开始条件不满足则不循环
8.3 do-while
语法: do {statement1, statement2, ...} while (condition)
[root@www ~]# awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd root x 0 bin x 1 daemon x 2 adm x 3 lp x 4 sync x 5 shutdown x 6
注:该循环不管条件是否满足,至少执行一次
8.4 for
语法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd
awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd
例;
用for语句找出sum.txt里边大于500的数字
[root@www ~]# awk '{for (i=1;i<=NF;i++){if($i>500) print $i}}' sum.txt 1231241235 3141 1321432546 53242 2131 1231 [root@www ~]#
for循环还可以用来遍历数组元素:
数组:一组连续的可存多个值的内存空间
例:bash ARRAY=(‘mon’’tue’’wed’) 那我们要向引用wed 则使用ARRAY[2] Bash;关联数组,利用字符串来引用另一个字符串,此时该字符串是另一个字符串的下表 例; ARRAY=(a=’mon’b=’tue’c=’wed’) 应用wed 使用ARRAY=[c] 这就是所谓的使用数组索引 语法: for (i in array) {statement1, statement2, ...}
例;显示当前系统上用的shell的种类及其个数
[root@www ~]# awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd /bin/sync:1 /bin/bash:3 /sbin/nologin:31 /sbin/halt:1 /sbin/shutdown:1 [root@www ~]#
显示当前系统tcp进程的不同端口的状态的个数
[root@www ~]# netstat -tan | awk '/^tcp/{state[$NF]++}END{for (S in state) print S,state[S]}' LISTEN 13 ESTABLISHED 1 [root@www ~]#
8.5 case
语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
8.6 break 和 continue
常用于循环或case语句中
8.7 next
提前结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户:
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
九 awk中使用数组
array[index-expression]
index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。
要遍历数组中的每一个元素,需要使用如下的特殊结构:
for (var in array) { statement1, ... }
其中,var用于引用数组下标,而不是元素值;
例子:
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引;
awk '{counts[$1]++}; END {for(url in counts) print counts[url], url}' /var/log/httpd/access_log
用法与上一个例子相同,用于统计某日志文件中IP地的访问量
十、awk的内置函数
split(string, array [, fieldsep [, seps ] ])
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从1开始的序列;
length([string])
功能:返回string字符串中字符的个数;
substr(string, start [, length])
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
system(command)
功能:执行系统command并将结果返回至awk命令
systime()
功能:取系统当前时间
tolower(s)
功能:将s中的所有字母转为小写
toupper(s)
功能:将s中的所有字母转为大写
例:显示当前文件系统使用比例大于等于%20的设备
[root@www ~]# df -lh Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg0-root 20G 691M 19G 4% / tmpfs 504M 0 504M 0% /dev/shm /dev/sda1 194M 38M 147M 21% /boot /dev/mapper/vg0-usr 9.9G 3.9G 5.5G 42% /usr /dev/mapper/vg0-var 20G 450M 19G 3% /var /dev/sr0 3.6G 3.6G 0 100% /media [root@www ~]# df -lh | awk '!/^File/{split($5,percent,"%");if(percent[1]>=20){print $1}}' /dev/sda1 /dev/mapper/vg0-usr /dev/sr0 [root@www ~]#