awk的调用方式与sed类似,脚本文件以#!/bin/awk -f或#!/bin/gawk -f开头。相比于grep和sed,awk正则表达式支持"?"和"+"两个拓展元字符。
- awk模式匹配
$ cat file
qwer
1234
[jin1ming@ML linux_shell]$ awk '/^$/{print "Hello World!"}' file
Hello World!
Hello World!
^$在此处用于匹配空行
- 记录和域
awk认为每行为一个记录,行中每个字符串为域,域之间用空格,Tab键或其他符号进行分隔,分隔域的是分隔符。(分隔符默认为空格)
$ cat phoneinfo
张三 湖南 123455
李四 山西 222222
王五 河南 333333
$ awk '{print $1}' phoneinfo
张三
李四
王五
$ awk '{print $1;{print $0}}' phoneinfo
张三
张三 湖南 123455
李四
李四 山西 222222
王五
王五 河南 333333
$ awk 'BEGIN{num=3} {print$num}' phoneinfo
123455
222222
333333
0代表所有域
awk处理时,将进行逐行扫描
BEGIN在遍历文件前执行
awk中可使用变量
$ awk 'BEGIN{OFS=";"} {print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS=";";OFS="::"} {print $1,$2,$3}'
张三::湖南::123455
李四::山西::222222
王五::河南::333333
OFS为输出域分隔符,FS为(输入)域分隔符
该demo,将文件中的空格作为域分隔符进行域划分,
将“;”作为域分隔符进行输出到管道,
最后将管道中的文本按“;”作为域分隔符进行域划分,
最后将“::”作为输出域分隔符进行输出。
#修改字符串之间的空格为两个
$ cat phoneinfo
张三 湖南 123455
李四 山西 222222
王五 河南 333333
$ awk 'BEGIN{OFS=","}{print $1,$2,$3}' phoneinfo
张三,湖南,123455
李四,山西,222222
王五,河南,333333
说明空格作为域分隔符时,空格可为1个或多个
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS=":";OFS=","} {print $1,$2,$3}'
张三,,湖南
李四,,山西
王五,,河南
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS="::";OFS=","} {print $1,$2,$3}'
张三,湖南,123455
李四,山西,222222
王五,河南,333333
其他符号作为域分隔符只代表其一个字符,若想多个,必须使用“+”,
例如 \t+代表一个或多个该字符(支持正则)
注意此处第一个命令,输出中第二个域为空域
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS="::";OFS=",";ORS=";"}
> {print $1,$2,$3}'
张三,湖南,123455;李四,山西,222222;王五,河南,333333;
ORS输出域分隔符,RS记录分隔符(默认都为换行符)
- 关系和布尔运算符
需注意:
1:~ 匹配正则表达式
2: !~ 不匹配正则表达式
其他运算符与c语言一致
$ awk 'BEGIN{FS=":"} $2~/dd/' 2.txt
2:dd
:ddddddd
- 表达式
统计行数
$ awk 'BEGIN{i=0} {print ++i}' 2.txt
1
2
3
4
5
计算每人平均分数
$ cat score
张三:78 92 87
李四:91 64 87
王五:34 99 56
$ cat awkdomo.awk
#!/bin/awk -f
BEGIN {FS="[: ]"}
{sum=$2+$3+$4
avg=sum/3
print $1,":",avg}
$ chmod u+x awkdomo.awk
$ ./awkdomo.awk score
张三 : 85.6667
李四 : 80.6667
王五 : 63
- 常用系统变量
以上提到的不再重复
ARGC 命令行参数的数量
ARGIND 命令行中当前文件的位置(以0开始标号)
ARGV 命令行参数的数组(ARGV[0]存储的是执行脚本的程序名)
FILENAME 当前文件名
NF 当前记录中的域数量
$ cat awkdomo.awk
#!/bin/awk -f
BEGIN{FS="[: ]"}
{print "\nARGC:",$ARGC,
"\nARGIND:",$ARGIND,
"\nARGV",$ARGV[2],
"\nFILENAME:",$FILENAME,
"\nNF:",$NF
}
$ ./awkdomo.awk score
ARGC: 78
ARGIND: 张三
ARGV 张三:78 92 87
FILENAME: 张三:78 92 87
NF: 87
ARGC: 91
ARGIND: 李四
ARGV 李四:91 64 87
FILENAME: 李四:91 64 87
NF: 87
ARGC: 34
ARGIND: 王五
ARGV 王五:34 99 56
FILENAME: 王五:34 99 56
NF: 56
- 格式化输出
printf (格式控制符,参数) ,与c语言一致 - 内置字符串函数
gsub(r,s) 在输入文件中用s替换r(全局替换)
gsub(r,s,t) 在t行中用s替换r
index(s,t) 返回s中字符串第一个t的位置
length(s) 返回s的长度
match(s,t) 测试s是否包含匹配t的字符串
split(r,s,t) 以t为分隔符将r进行分割,保存到数组s
sub(r,s,t) 将t中第一次出现的r替换为s
substr(r,s) 返回字符串r中从s开始的后缀部分
substr(r,s,t) 返回字符串r中从s开始长度为t的后缀部分
- 向awk脚本传递参数
awk -f 脚本文件 parameter=value 输入文件
或
awk [awk命令] parameter=value 输入文件
$ awk '
BEGIN{n = 999; print n}
{if (n==1) print "Continue!"
} ' n=1 2.txt
999
Continue!
Continue!
Continue!
Continue!
Continue!
参数赋值在BEGIN后执行
- 条件语句和循环语句
和c语言完全一致,在判断时可以使用~匹配符和正则表达式作为if语句的条件 - 数组
awk数组的形式和c语言一致,只是无需定义就可以使用,需要注意的是数组下标不是必须为整数,可以为浮点数或字符串,而且09和9作为下标是不一样的
$ awk '
BEGIN{nums[1.5]=5.1} {print nums[1.5];print nums[1]}
' score
5.1
5.1
5.1
$ awk '
BEGIN{nums[wer]=9;nums[2]=2;nums[9]=9}
END {for (var in nums)
print var,":",nums[var]
}' score
: 9
9 : 9
2 : 2
数组和参数相结合的根据姓名查询个人信息
$ cat awkdomo2.awk
#!/bin/awk -f
BEGIN{
if(ARGC>2){
name=ARGV[1];
delete ARGV[1] }
else{
while(!name){
print "请输入姓名:";
getline name< "-"}
}
}
$1~name {print $1,$2,$3}
./awkdomo2.awk 张三 phoneinfo
张三 湖南 123455
输入姓名使用read将会使得"请输入姓名:"疯狂输出,原因还尚未琢磨清楚
网友评论