文章目录
awk
awk是强大的文本处理工具,既可以应对文本分割,也可以对数据进行统计,上手后十分方便快捷
这里简单记录一下使用心得和技巧,以备不时之需
内置变量
awk中的若干内置变量可以直接在脚本中使用而不需要声明,其中一部分可以直接使用option设置来修改分割方式
- RS(record-separator) /FS(filed-separator)
这两个是分割控制符,用来控制record和field的分割方式,默认RS为换行FS为空格。
对应到脚本中,默认循环遍历对应的每一个record,输出的$1$2对应的是每个record的filed。
其中FS最常用可以使用-F直接指定,如果是多种分割符的话用方括号括起来中间的每个字符都是分割符(这里可. 能是类似正则方式表达,具体还不太确定待考证)
awk -F"[|.,]" '{print $2, $4, $NF}' xxxx.log
-
ORS(output-record-separator)/OFS(output-filed-separator)
与之相对应的还有输出的分割(叫连接更好点)控制符。
其中OFS是用在print多项时候起作用
这四个都是可以在option中赋值修改的 -
NR(number-of-record) NF(number-of-field)
两者分别表示当前的record的编号和当前record分割后有多少field(也可以理解为field编号)
这两个全部都是从1开始计数
另外还有一个FNR,是在多个文件被awk处理时,表示record在其文件内的编号,NR表示的是全局的编号
参数
函数
排序函数
脚本中可以直接使用字典不用先定义,然后有两个排序函数可以完成对字典的排序
length=asort(ori, dest)
其中length返回的是排序后的数量,ori是传入的字典dest是排序后的字典,两个函数都是这么使用
asort 对value排序(可以数字排序)
排序后的新字典是以 编号->value 的形式存在,所以会丢失key的内容
asorti 对key排序(字符串排序)
排序后的字典的key的顺序就是排序后的顺序
两者排序后都应该使用for(i=1;i<length;i++)的方式遍历,for in的结果是无序的
清屏函数fflush
在脚本内使用fflush();
函数清掉缓冲区输出
字符串分割
`split($2, tmp, ",")` 把第二个字段按照逗号分割,并将结果存入tmp数组,不改变原字符串$0
正则替换
`sub(/regix/ , "|", $2 )` 在第二个字段中使用regix正则匹配,并将匹配到的第一个替换为竖线,全部替换使用gsub函数
正则提取
`match($2, /regix/, tmp)` 从第二个字段中获取正则匹配上regix的部分存入数组tmp
脚本部分
脚本三段
‘BEGIN{} {} END{}‘
BEGIN和END分别表示后面跟的大括号的内容为 遍历前 遍历后 执行,只执行一次
中间单独的大括号为遍历循环的整体,里面的内容会执行NR次
对于分割后的内容用$1 $2 $3 … 来表示第几个field,特殊的$0表示完整的当前record
数组删除元素
使用delete
关键字可以删除数组中的一个元素
输出清屏
使用system("clear")
来刷新terminal输出屏幕
可以用system()
调用Linux的命令
输出日期时间
print strftime("%D %T",systime());
格式化字符串
printf换成sprintf可以实现 并且格式化后的字符串不是输出而是作为返回值返回
ret = sprintf("%s\n", str);
格式化输出
可以使用printf(),与c语言里的printf几乎完全一样的格式化方式很容易上手。
重定向&&管道
管道可以直接加双引号使用,但是注意需要关闭管道
实现sort排序的一种思路
最后放两个例子,可以从中捞点干货例子
竖列求和
#统计当前目录下压缩文件和普通文件
ls -l |grep "tar\.gz"
ls -l |grep -v "tar\.gz"
#grep 最好加双引号并加上转义
[root@10-19-60-16 trafficdatapush_data]# ls -l |grep "tar\.gz" | head -5
-rw-r--r-- 1 root root 45 Apr 12 13:16 20180930_11.test.result.tar.gz
-rw-r--r-- 1 root root 4368364 Apr 12 14:07 20181011_09.onlined.result.tar.gz
-rw-r--r-- 1 root root 37920105 Apr 12 14:07 20181011_10.onlinec.result.tar.gz
-rw-r--r-- 1 root root 3835136 Apr 12 14:07 20181011_10.onlined.result.tar.gz
-rw-r--r-- 1 root root 91688929 Apr 12 14:07 20181011_10.test.result.tar.gz
#要统计总大小,第五列求和
ls -l |grep "tar\.gz" |awk -F " *" '{sum+=$5; print $5","sum} END {print sum}'
# -F“ *” 指定分隔符,多个连续空格为分隔符,不然会严格一一个空格分割
# '....'单引号中是具体操作
# {sum+=$5; print $5","sum} 对于每一行sum+=第五列($0是完整的当前行)
# END {print sum} 最后所有行结束之后输出sum
日志的耗时统计
# ori_data
cat $1| egrep "^2021-03-08 20" | grep -v "load scene\|request logstr\|get_flow\|load_flow_info\|finish reload\|infostream_data_manager\|book_column_cache" |awk -F"[|.,]" '{print $2, $4, $NF}' >$2.ori
# new file
echo "" > $2.ret
# task cost avg
echo "sum count avg name"| awk 'END{printf("%10s, %10s, %7s, %s\n", $1,$2,$3,$4)}' >> $2.ret
cat $2.ori |awk -F" " 'BEGIN{OFS="\t"} {cnt[$1]++;sum[$1]+=$3;} END{for (k in cnt){printf("%10d, %10d, %7.3f, %s\n", sum[k], cnt[k], sum[k]/cnt[k], k)} }' >> $2.ret
echo -e "\n\n"
# each task detail
tasks=`cat ${2}.ori |head -100| awk '{print $1}'|sort|uniq|xargs`
for task in ${tasks[*]} ;do
echo -e "\n${task}"
cat $2.ori | grep $task |awk 'BEGIN{
max=0;
min=999;
}
{
if($3>max)max=$3;
if($3<min)min=$3;
range=int(($3)/10);
cnt[range]++;
total++;
keys[range]=range;
}
END{
l=asort(keys, keys);
printf "lsum_pct|";sum=0;
for(i=1;i<=l;i++){sum+=cnt[keys[i]];printf("%7.3f%% ", sum/total*100)};print "";
printf "percent |";
for(i=1;i<=l;i++){printf("%7.3f%% ", cnt[keys[i]]/total*100)};print "";
printf "count |";
for(i=1;i<=l;i++){printf("%8d ", cnt[keys[i]])};print "";
printf "range |";
for(i=1;i<=l;i++){printf("%7d+ ", keys[i]*10)};print "";
printf("max cost:%4d, min cost:%4d", max, min);
print "";
}' >> $2.ret
done
echo -e "\n\n"