标签:awk
在linux中,处于处理文件主要有三个指令,分别为grep、sed以及awk,grep主要是用于文本过滤,sed为行编辑器,awk则为报表生成器,以格式化文本输出。awk有点类似于cut,可以将一条条文本以某分隔符来分隔,然后取得相应的分隔的段。与cut不同的是,awk将一条条的文本信息首先读取到内存空间,然后进行相应的操作,awk中可以执行变量、格式化输出、运用数组还有函数等,是个非常强大的命令。
基本用法:
awk [options] ‘program‘ file file ...
选项:
-F[]:指明输入字段分隔符;
-v var=val: 变量赋值
program:
PATTERN { ACTION STATEMENT }
由语句组成,语句分隔符是;
ACTION: print, print
1、awk的输出命令print
print item1, item2, ...
要点:
(1) 各item间使用逗号分隔,而输出时则使用输出分隔符分隔;
[root@www ~]# awk -F: ‘{print $0}‘ /etc/group 显示的是group中所有的字段
[root@www ~]# awk -F: ‘{print $1}‘ /etc/group 显示的是以:分隔符的所有第一个字段
(2) 输出的各item可以字符串或数值、当前记录的字段($n)、变量或awk的表达式;数值会被隐式转换为字符进行输出
例:文件有多少行则会输出多少行的user 11
(3) print后面的item如果省略,相当于print $0,$0为整条文本; 输出“空白”,使用print "";
[root@www ~]# awk -F : ‘{print }‘ /etc/fstab 不会修改的输出的屏幕
[root@www ~]# awk -F : ‘{print " " }‘ /etc/fstab 输出的全都为空白行
2、变量
2.1 内置变量
FS: input field seperator,输入字段分隔符,默认为空白字符;
[root@www ~]# awk -v FS=: ‘{print $1,$3}‘ /etc/passwd 将赋值到FS中,作为分隔符
RS:input record separator,行分隔符, 默认为换行符;
awk -v RS=" " ‘{print $0 }‘ /etc/passwd 以空格为换行符
awk -v RS="[:/]" ‘{print }‘ /etc/passwd以:或/为换行符
OFS: output field seperator,输出时的字段分隔符默认为空白字符;
例:以 --为分隔符
ORS:output record separator,输出时的分隔符, 默认为换行符;
例: 以 --为换行符
NF: number of field in current record,字段数;
awk ‘{print NF}‘ /etc/fstab 此处为单引号‘ NF为变量,非字符串
awk ‘{print $NF}‘ /etc/fstab 打印出的每一行最后一个字段;
NR:行数,所有文件统一计数;
awk ‘{print NR}‘ /etc/fstab
awk ‘{print NR,$0}‘ /etc/fstab 显示行数以及行内容
FNR:行数,各文件分别计数;
awk ‘{print FNR}‘ /etc/fstab /etc/issue
awk ‘{print FNR}‘ /etc/fstab /etc/issue 显示两个文件的行数以及内容
FILENAME:当前文件名;
ARGC:命令行参数的个数;
awk ‘{print ARGC}‘ /etc/fstab /etc/issue
ARGV:数组,保存了命令行参数;
awk ‘{print ARGV[1]}‘ /etc/fstab /etc/issue
2.2 自定义变量
-v var=val:
变量名区分字符大小写
定义变量的位置:
(1) 可以program中定义变量;
awk -F: ‘{file="222";print file,$3}‘ /etc/passwd 得到的结果为如下图:
(2) 通过-v选项定义变量;
[root@www ~]# awk -F: -v file=222 ‘{print file,$3}‘ /etc/passwd
得到的结果与上面的相同。
3、printf命令
格式: printf format, item1, item2, ...
要点:
(1) format是必须的;
(2) 不会自动换行,需要显示指定换行符: \n
(3) format中需要分别为后面的每个item指定一个格式符;
格式符:都以%开头,后跟一个字符
%c: 显示字符的ASCII码;
%d,%i: 显示十进制整数;
awk ‘BEGIN{printf "%d",6.11}‘ 得到的结果为6,不过没有换行,直接输出
awk ‘BEGIN{printf "%d\n",6.11}‘ 换行后输出6
awk ‘BEGIN{printf "%d\n,%d\n",6.11,88.7}‘ 两个十进制整数
%e, %E: 科学计数法显示数值;
%f: 显示为浮点数;
%g, %G: 以科学计数法格式或浮点数格式显示数值;
%s: 字符串
%u: 无符号的整数
%%: 显示%自身
例:如下第一个%s相对应得到的是$1的字段,第二个%d相对应得到$3
[root@www ~]# awk -F: ‘{printf "this is user %s ,his UID is %d.\n" ,$1,$3}‘ /etc/passwd
this is user root ,his UID is 0.
this is user bin ,his UID is 1.
this is user daemon ,his UID is 2.
this is user adm ,his UID is 3.
this is user lp ,his UID is 4.
this is user sync ,his UID is 5.
this is user shutdown ,his UID is 6.
修饰符:
#[.#]: 第一个#指定显示宽度,例如%30s;第二个#表示小数点后的精度;
20为前面的长度,14为后面可显示的长度
-: 左对齐
+:显示数值符号
4、操作符:
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 负值
+x: 转换为数值
[root@www ~]# awk ‘BEGIN{print 4*7}‘
28
[root@www ~]# awk ‘BEGIN{print 14/7}‘
2
赋值操作符:
=, +=, -=, *=, /=, %=, ^=
++, --
[root@www ~]# awk -v f1=4 ‘BEGIN{f1-=2;print f1}‘
2
比较操作符:
>, >=, <. <=, ==, !=
模式匹配符:
~ 是否能由右侧指定的模式所匹配;
!~ 是否不能由右侧指定模式所匹配;
逻辑操作符:
&&
||
条件表达式:
selector?if-true-expression:if-false-expression
例子:
awk -F: ‘{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}‘ /etc/passwd awk -F: ‘{$3>=500?usertype="common":usertype="system";print $1,usertype}‘ /etc/passwd
函数调用:
function_name(argu1,argu2,...)
5、PATTERN
(1) /regular expression/: 仅处理能够被/regular expression/所匹配到的行;
如:在/etc/passwd中以root为行首的单词的,以:为分隔符,打印出第一个和第三个字段:
[root@www ~]# awk -F: ‘/^\<root\>/{print $1,$3}‘ /etc/passwd
root 0
如:在/etc/passwd中以a或b开头,以:为分隔符的第一个和第三个字段;
[root@www ~]# awk -F: ‘/^[ab]/{print $1,$3}‘ /etc/passwd
bin 1
adm 3
avahi-autoipd 170
abrt 173
apache 48
(2) relational expression:关系表达式,有真假之分,一般来说,其结果为非0或非空字符串时为“真”,否则,为“假”;
如:以:为分隔符,第三段大于等于500的行,打印第一、三、六段;
[root@www ~]# awk -F: ‘$3>=500{print $1,$3,$6}‘ /etc/passwd
nfsnobody 65534 /var/lib/nfs
11 500 /home/11
22 501 /home/22
33 502 /home/33
如:以:为分隔符,第五段为root的行
[root@www ~]# awk -F: ‘$5~/root/{print$0}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
(3) line ranges:行范围,类似sed或vim的地址定界法;startline, endline
(4) BEGIN/END: 特殊模式
BEGIN:仅在awk运行程序之前执行一次(BEGIN),通常用于输出表头或做出一个预处理操作;
END:仅在awk运行程序之后执行一次(END);通常用于输出表尾或做出清理操作;
[root@www ~]# awk -F: ‘BEGIN{print "aaaa"}$5~/root/{print $0}END{print "bbbb"}‘ /etc/passwd
aaaa
root:x:0:0:root:/root:/bin/bash
bbbb
(5) empty: 空模式,匹配任意行;
6、常用的action
(1) Expressions:例如变量赋值
(2) Control statements:控制语句,如if、while等
(3) Compound statements:复合语句
(4) input statements:输入语句
(5) output statements:输出语句
7、控制语句
if (condition) statement [ else statement ]
while (condition) statement
do statement while (condition)
for (expr1; expr2; expr3) statement
for (var in array) statement
break
continue
delete array[index]
delete array
exit [ expression ]
{ statements }
7.1 if-else
语法:if (condition) statement [ else statement ]
if (condition) { statements; } [ else { statements; }]
如:以:为分隔符,第三段大于等于500,则输出第一段加is a common user.
[root@www ~]# awk -F: ‘{if($3>=500) print$1,"is a common user."}‘ /etc/passwd
nfsnobody is a common user.
11 is a common user.
22 is a common user.
33 is a common user.
如:以:为分隔符,第三段大于等于500,则输出第一段加is a common user.否则为第一段加is a system user or admin
[root@www ~]# awk -F: ‘{if($3>=500) {print $1,"is a common user."}else{print $1,"is a system user or admin"}}‘ /etc/passwd
如:以:为分隔符,打印出第三段等于第三段的行;
[root@www ~]# awk -F: ‘{if ($3==$4) {print $0}}‘ /etc/passwd
如:打印出字段数大于6的行以及相对应的字段数;
[root@www ~]# awk ‘{if (NF>=6) print NF,$0}‘ /etc/rc.d/rc.sysinit
如:显示出挂载大于29的挂载磁盘分区
[root@www ~]# df -lh | awk -F" " ‘!/^File/{if ($2>29) print $1,$2}‘
tmpfs 491M
/dev/mapper/vg0-usr 9.8G
/dev/sda3 9.8G
7.2 while循环
语法:while (condition) statement
while (condition) { statements }
条件为真时进行循环,直到为假退出;
用法:通常用于在当前行的各字段间进行循环;
如:打印每行中每个词段的长度;
~]# awk ‘{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}‘ /etc/inittab
如: 显示出单词长度大于5的词段以及单词的长度;
~]# awk ‘{i=1;while(i<=NF){if (length($i)>5) {printf "%20s:%d\n",$i,length($i);} i++}}‘ /etc/inittab
7.3 do-while循环
语法:do statement while (condition)
do { do-while-body } while (condition)
意义:至少执行一次循环体;
7.4 for循环
语法:for (expr1; expr2; expr3) statement
for (expr1; expr2; expr3) { statements }
for (varaiable assignment; condition; iteration process) { for-body }
如: 打印每行中每个词段的长度;
awk ‘{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}‘ /etc/inittab
for循环在awk中有一个专用于遍历数组元素:
语法:for (var in array) { for-body }
7.5 switch
语法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}
7.6 break and continue
break [n]: 退出当前循环
continue:提前结束本轮循环,直接进入下轮循环
7.7 next
提前结束对本行的处理而进入下一行的处理
如:打印出第三段为偶数的第一和第三段
~]# awk -F: ‘{if($3%2!=0) next;print $1,$3}‘ /etc/passwd
8、Array
关联数组:array[index-expression]
index-expression:
可以使用任意字符串;
如果某数组元素事先不存在,在引用时,awk会自动创建此元素并将其值初始化为空串;
因此,若要判断数组是否存在某元素,要使用“index in array”进行;
a[mon]="Monday"
print a[mon]
[root@localhost ~]# awk ‘BEGIN {a[aa]="pp"; print a[aa]}‘
pp
要遍历数组中的每个元素,使用: for (var in array) { for body }
注意:var会遍历array的每一个索引,print array[var]
例子:统计每一行中各单词分别出现的次数
可定义一个数组,用单词本身当索引,而元素的值存储单词出现的次数
~]# awk ‘{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}‘ awk.txt 整个文件统一统计
~]# awk ‘{for(i=1;i<=NF;i++) {count[$i]++}}{for(j in count) {print j,count[j]};delete count}‘ awk.txt 每行单独统计
先遍历每个字段赋值与count[$i]
例:查看ss状态中,第一段中状态出现的次数以及状态
~]# ss -tan | awk ‘!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}‘
ESTAB 2
CLOSE-WAIT 1
LISTEN 18
例:查看网络状态中,第后段中状态出现的次数以及状态
[root@www ~]# netstat -tan | awk ‘/^tcp/{state[$NF]++}END{for(i in state){print i ,state[i]}}‘
CLOSE_WAIT 1
ESTABLISHED 2
LISTEN 18
统计httpd访问日志中,每个IP出现的次数;
~]# awk ‘{ip[$1]++}END{for(i in ip){print i,ip[i]}}‘ /var/log/httpd/access_log
遍历第一个字段$1 ,赋值于ip数组内,END后是打印出字段以及次数
9、函数
9.1 内置函数
数值处理:
rand(): 返回0和1之间一个随机数;
字符串处理:
length([s]): 返回指定字符串的长度
例:
[root@www ~]# awk ‘BEGIN {print length("hello")}‘
5
sub(r, s [, t]):以r所表示的模式来查找t字符串中的匹配,将其第一次出现替换同s所表示的字符串;
sub(ab,AB,$0)
gsub(r, s [, t]):以r所表示的模式来查找t字符串中的匹配,将其所有的出现均替换同s所表示的字符串;
split(s, a [, r]): 以r为分隔符切割字符串s,并将切割的结果保存至a表示数组中;
例: 以:为分隔符来切割字符串$0,即为/etc/passwd中的行,并将切割后的第一个字段保存在数组保 存在userinfo中,吧打印出来;
awk ‘{split($0,userinfo,":");print userinfo[1]}‘ /etc/passwd
例:显示出网络状态中以tcp开头第五段中出现的ip以及次数
netstat -tan | awk ‘/^tcp/{len=split($5,client,":");ip[client[len-1]]++}END{for(i in ip){print i,ip[i]}}‘
时间类的函数:
systime(): 取时间戳;
位运算函数:
and(v1,va2):
9.2 自定义函数
function f_name(p,q)
{
...
}
以上为awk的常用用法,以及一些示例。
标签:awk
原文地址:http://jimchen.blog.51cto.com/10026955/1654082