log.txt文本内容如下:

1
2
3
4
2 this is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ls -l | awk '{print $1,$5}' 					$n 代表输出第几列
ls -l | awk '{print $1,$5}' OFS=" | " OFS标识以 " | " 对输出结果分割

awk -F, '{print $1,$2}' log.txt # -F, 使用","分割

awk '$1>2' log.txt 过滤第一列大于2的行
awk '$1==2 {print $1,$3}' log.txt #过滤第一列等于2的行,输出1,3列

ls -l | awk '$5>1000 {print $1,$5}' OFS=" | " 输出ls中大于1000的文件
ls -l | awk '$5>1000 && $5<10000 {print $1,$5}' OFS=" | " 输出ls中大于1000且小于10000的文件


ls -l | awk 'BEGIN{dirNum=0;}{ if($1 ~ /^d/){res[dirNum++]=$9;print dirNum;}} END{ for(i=0;i<dirNum;i++){ print res[i]; } } ' # 输出目录 $9 代表了ls -l的第九列 $1 ~ /^d/ 中呢规则匹配开头是d的

设置普通变量

1
2
3
4
5
6
7
8
9
10
11
12
13
awk -v  # 设置变量
$ awk -va=1 '{print $1,$1+a}' log.txt
---------------------------------------------
2 3
3 4
This's 1
10 11
$ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt $1b是直接结合字符串变量
---------------------------------------------
2 3 2s
3 4 3s
This's 1 This'ss
10 11 10s

字符串连接

1
2
3
4
5
6
7
将变量与””符号连接起来运算即可
[chengmo@centos5 ~]$ awk 'BEGIN{a="a";b="b";c=(a""b);print c}'
ab

通过”+”连接运算。自动强制将字符串转为整型。非数字变成0,发现第一个非数字字符,后面自动忽略。
[chengmo@centos5 ~]$ awk 'BEGIN{a="a";b="b";c=(a+b);print c}'
0

数组变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sites["runoob"]="www.runoob.com";
sites["google"]="www.google.com"
delete sites["google"]; // 删除
print fruits["google"]

模拟二维数组
array["0,0"] = 100;
array["0,1"] = 200;
array["0,2"] = 300;
array["1,0"] = 400;
array["1,1"] = 500;
array["1,2"] = 600;
# 输出数组元素
print "array[0,0] = " array["0,0"];
print "array[0,1] = " array["0,1"];
print "array[0,2] = " array["0,2"];
print "array[1,0] = " array["1,0"];
print "array[1,1] = " array["1,1"];
print "array[1,2] = " array["1,2"];
数组典型应用
1
2
3
4
1. 用 awk 中查看服务器连接状态并汇总
netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' # $NF 代表了最后一个字段State
ESTABLISHED 1
LISTEN 20

image-20201003075807666

1
2
3
4
5
6
7
8
9
10
11

2. 统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总
awk '{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print
"total size is :"total}' /app/log/access_log
total size is :172230
21 /icons/poweredby.png 83076
14 / 70546
8 /icons/apache_pb.gif 18608
a[$7]+=$10 表示以第 7 列为下标的数组( $10 列为$7 列的大小),把他们大小累加得到
$7 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一
for 语句足矣

条件判断 for循环

1
2
3
4
5
6
7
8
9
10
11
$ awk 'BEGIN {
a=30;
if (a==10)
print "a = 10";
else if (a == 20)
print "a = 20";
else if (a == 30)
print "a = 30";
}'

$ awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'

自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 返回最小值
function find_min(num1, num2)
{
if (num1 < num2)
return num1
return num2
}

# 返回最大值
function find_max(num1, num2)
{
if (num1 > num2)
return num1
return num2
}

# 主函数
function main(num1, num2)
{
# 查找最小值
result = find_min(10, 20)
print "Minimum =", result

# 查找最大值
result = find_max(10, 20)
print "Maximum =", result
}

# 脚本从这里开始执行
BEGIN {
main(10, 20)
}

awk脚本

1
2
3
4
awk -f {awk脚本} {文件名}

实例:
$ awk -f cal.awk log.txt
ls.awk

脚本分为 开头,正文,结尾 三部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
BEGIN {
#FS="," ; # 以空格分割
OFS=" | " ; # print 结果用 | 分割
#print "done"; # 调试用,如果输出done就知道BEGIN这段代码执行了
No = "序号";
Permisson = " 权 限";
HardLink = "硬链接数"; # 如果一个文件不是目录,此时ls第二个字段表示这个文件所具有的硬链接数
SymbolicLinks = "软链接";
SubDir = "子目录数"; # 如果是一个目录,则第2字段表示该目录所含子目录的个数(不包含文件在内)
Owner = "所属用户";
Size = "大小";
LastModified = "最近修改";
Name = "名称";

no = 0;
dirNum = 0; # 统计目录数量
fileNum = 0; # 统计文件数量
Total = 0; # 总用量

printf "-------------------------\n\n";
printf "[普通文件]: \n";
printf "%-10s %-6s %-6s %-8s %-8s %-s\n",Permisson,HardLink,Owner,Size,LastModified,Name;
};

{
if ($1 ~ /^d/){ # 看这一行的第一列是d开头代表目录,就先存起来
res[Permisson""dirNum] = $1;
res[SubDir""dirNum] = $2;
res[Owner""dirNum] = $3;
res[Size""dirNum] = $5;
res[LastModified""dirNum] = $6;
res[Name""dirNum] = $9;
dirNum++;
}else{
if(NR == 1){ # 第一行总用量字段暂存
Total = $2;
}else{
fileNum++;
printf "%-15s %-8s %-9s %-13s %-8s %-s \n", $1,$2,$3,$5,$6,$9;
}
}
}

END{
printf "-------------------------\n\n";
printf "[目录]: \n";
printf "%-10s %-6s %-6s %-8s %-8s %-s\n",Permisson,SubDir,Owner,Size,LastModified,Name;

for (i=0;i<dirNum;i++) # 输出所有目录
printf "%-15s %-8s %-9s %-13s %-8s %-s \n", res[Permisson""i],res[SubDir""i],res[Owner""i],res[Size""i],res[LastModified""i],res[Name""i];

printf "-------------------------\n";
printf "[总用量]: %s\n",Total;
printf "[目录数量]: %s\n",dirNum;
printf "[文件数量]: %s\n",fileNum;
}

image-20201003074806101

常用字符串函数

image-20201003075914199

字符串函数的应用

  1. 替换

    1
    2
    3
    awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!
    在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未
    给 info 值,默认是$0
  2. 查找

    1
    2
    awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'
    ok #未找到,返回 0
  3. 匹配查找

    1
    2
    awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'
    ok #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
  4. 截取

    1
    2
    awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'
    s is a tes #从第 4 个 字符开始,截取 10 个长度字符串
  5. 分割

    1
    2
    3
    4
    awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4
    4 test 1 this 2 is 3 a
    #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。 并不是从数组下标
    1…n 开始

内建变量

变量 描述
$n 当前记录的第n个字段,字段间由FS分隔
$0 完整的输入记录
ARGC 命令行参数的数目
ARGIND 命令行中当前文件的位置(从0开始算)
ARGV 包含命令行参数的数组
CONVFMT 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO 最后一个系统错误的描述
FIELDWIDTHS 字段宽度列表(用空格键分隔)
FILENAME 当前文件名
FNR 各文件分别计数的行号
FS 字段分隔符(默认是任何空格)
IGNORECASE 如果为真,则进行忽略大小写的匹配
NF 一条记录的字段的数目
NR 已经读出的记录数,就是行号,从1开始
OFMT 数字的输出格式(默认值是%.6g)
OFS 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符
ORS 输出记录分隔符(默认值是一个换行符)
RLENGTH 由match函数所匹配的字符串的长度
RS 记录分隔符(默认是一个换行符)
RSTART 由match函数所匹配的字符串的第一个位置
SUBSEP 数组下标分隔符(默认值是/034)