awk是linux下的一个命令,他对其他命令的输出、对文件的处理都十分强大,其实他更像一门编程语言,可以自定义变量、条件语句、循环、数组、正则、函数等。可以读取输出,读取文件的方式是一行一行的读,根据给出的条件进行查找,并在找出来的行中进行操作。awk有三种形势,awk,gawk,nawk

awk中的记录,域,分割符

读取输出或者读取文件时,读取一行就是一个记录。记录分割符默认是回车符,保存在RS,ORS中。

从记录中分割出需要单词或者词组时,行中的每个字符串定义为域,域分割符默认是空格和TAB符,保存在ORS中。

举个例子:

1
2
aaaa:bbbb:ccccccc
1111:2343:5t43343

上面有二行,这二行就是二个记录,每行后面的回车呢,就是记录分割符,里面冒号呢,就是域分割符,分割出来的aaaa、1111这类东西就是域了。

1
awk -F: '{print $1}' testfile

awk的内建变量和运算符

  1. 变量
变量 描述
$n 当前记录的第n个字段,字段间由 FS分隔
$0 完整的输入记录
ARGC 命令行参数的数目
ARGIND 命令行中当前文件的位置(从0开始算)
ARGV 包 含命令行参数的数组
CONVFMT 数字转换格式(默认值为%.6g)
ENVIRON 环境变量关联数组
ERRNO 最后一个系统错误的描述
FIELDWIDTHS 字 段宽度列表(用空格键分隔)
FILENAME 当前文件名
FNR NR但相对于当前文件
FS 字段分隔符(默认是任何空格)
IGNORECASE 如果为真,则进行忽略大小写的匹配
NF 当前记录中的字段数
NR 当前记录数
OFMT 数字的输出格式(默认值是%.6g)
OFS 输出字段分隔符(默认值是一个空格)
ORS 输出记录分隔符(默认值是一个换行符)
RLENGTH match函数所匹配的字符串的长度
RS 记录分隔符(默认是一个换行符)
RSTART match函数所匹配的字符串的第一个位置
SUBSEP 数组下标分隔符(默认值是\034)
  1. 运算符
运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|| 逻辑或
&& 逻辑与
~ ~! 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加 减
* / & 乘,除与求余
! 逻辑非
^ *** 求幂
++ – 增加或减少,作为前缀或后缀
$ 字段引用
in 数组成员

awk的正则

匹配符 描述
\Y 匹配一个单词开头或者末尾的空字符串
\B 匹配单词内的空字符串
< 匹配一个单词的开头的空字符串,锚定开始
> 匹配一个单词的末尾的空字符串,锚定末尾
\W 匹配一个非字母数字组成的单词
\w 匹配一个字母数字组成的单词
' 匹配字符串末尾的一个空字符串
\‘ 匹配字符串开头的一个空字符串

awk的函数

  1. 字符串函数
函数名 描述
sub 匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的 时候
gsub 整个文档中进行匹配
index 返回子字符串第一次被匹配的位置,偏移量从位置1开始
substr 返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串
split 可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割
length 返回记录的字符数
match 返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位 置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串
toupper和tolower 可用于字符串大小间的转换,该功能只在gawk中有效
  1. 数学函数
函数名 返回值
atan2(x,y) y,x 范围内的余切
cos(x) 余弦函数
exp(x) 求幂
int(x) 取整
log(x) 自然对数
rand() 随机数
sin(x) 正弦
sqrt(x) 平方根
srand(x) x是rand()函数的种子
int(x) 取整,过程没有舍入
rand() 产生一个大于等于0而小于1的随机数

实例

学习awk的时候,做了一个例子,学东西,不要光看,光看是记不住东西的。光看的话,也许你知道怎么回事,真正实际操作,不是这儿有问题,就是那儿有问题。所以一定要动手亲自操作一下。

  1. 测试文件test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
mail:x:8:12:mail:/var/spool/mail:/bin/false
ftp:x:14:11:ftp:/home/ftp:/bin/false
&nobody:$:99:99:nobody:/:/bin/false
zhangy:x:1000:100:,,,:/home/zhangy:/bin/bash
http:x:33:33::/srv/http:/bin/false
dbus:x:81:81:System message bus:/:/bin/false
hal:x:82:82:HAL daemon:/:/bin/false
mysql:x:89:89::/var/lib/mysql:/bin/false
aaa:x:1001:1001::/home/aaa:/bin/bash
ba:x:1002:1002::/home/zhangy:/bin/bash
test:x:1003:1003::/home/test:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po

例1:

1
2
3
4
5
6
7
8
9
cat test | awk -F: '{\
if ($1 == "root"){\
print $1;\
}else if($1 == "bin"){\
print $2;\
}else{\
print $3;\
} \
}'

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
awk '{\
for(i=0;i<NF;i++){\
if ($i ~/^root/){\
print $i;\
}else if($i ~/zhangy/){\
print $i;continue;\
}else if($i ~/mysql/){\
print $i;next;\
}else if($i ~/^test/){\
print $i;break;\
} \
}\
}' test

例3:

1
2
3
tail test | awk 'BEGIN{while(getline d){ split(d,test);for(i in test){\
print test[i]\
}}}'

例4:

1
2
3
ls -al ~/test | awk 'BEGIN{while(getline d){ split(d,test);\
print test[9] ;}
}'

例5:

1
2
3
4
5
6
7
8
9
echo "32:34" |awk -F: '{print "max = ",max($1,$2)}\
function max(one,two){\
if(one > two){\
return one;\
}else{\
return two;\
}\
}\
'

例6:

1
2
3
4
5
6
7
8
#awk 'BEGIN{print "what is your name"; getline name < "/dev/tty"}$1 ~name{print
#"found name on line" NR}END{print "see you" name}' test
#awk '{sub(/daemon/,"tankzhang");print}' test
#awk '{ {sub(/zhangy/,"tankzhang");$1};print}' test
#awk '{ {gsub(/zhangy/,"tankzhang");$1};print}' test
#awk -F: '{print index("zhangy",$1)}' test
#awk -F: '{print substr($1,1,2)}' test
awk -F: '{mat=match($1,/^[a-zA-Z]+$/);print mat,RSTART,RLENGTH}' test

例7:

1
2
3
4
5
cat test |awk -F: '\
NF != 7{\
printf("line %d,does not have 7 fields:%s\n",NR,$0)}\
$1 !~ /^[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%s: %s\n",NR,$1,$0)}\
$2 == "*" {printf("lind %d,no password:%s\n",NR,$0)}'