Awk是Linux系统中一个优秀的样式扫描与处理工具,要说awk的命令的起源,事实上,它是三个人名的缩写:Aho、Peter Weinberg、Brain Kernighan,因为是他们创造的awk。
Awk功能非常强大:除了可以完成grep和sed所能完成的全部工作,还可以进行样式装入、流控制、数学运算符、进程控制语句等等。与其说awk是一个工具,不如是一种程序设计语言:awk程序设计语言,因为创建者已将它正式定义为“样式扫描和处理语言”。
本文将通过各种实例,来展示awk的功能。
语法
awk [参数] 'BEGIN{} //{命令1; 命令2; ...} END{}' 文件1 文件2 ...
参数说明
参数说明
参数 | 说明 |
-F fs 或 --field-separator fs | 指定分隔符,fs为字符串或正则表达式 |
-f scripfile 或 --file scriptfile | 调用脚本,从脚本文件中读取awk命令 |
-v var=value 或 --asign var=value | 定义变量 |
-W compact 或 --compat -W traditional 或 --traditional |
在兼容模式下运行awk。gawk和标准awk的行为一样,但忽略所有awk扩展 |
-W copyleft 或 --copyleft -W copyright 或 --copyright |
打印简短的版权信息 |
-W help 或 --help -W usage 或 --usage |
打印全部awk选项和每个选项的简短说明 |
-W lint 或 --lint | 打印不能向传统unix平台移植的结构的警告 |
-W lint-old 或 --lint-old | 打印关于不能向传统unix平台移植的结构的警告 |
-W posix | 打开兼容模式。不识别:/x、函数关键字、func、换码序列;当fs是一个空格时将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效 |
-W re-interval 或 --re-inerval | 允许使用间隔正则表达式,参考(grep中的Posix字符类),如:[[:alpha:]] |
-W source program-text 或 --source program-text | 使用program-text作为源代码,可与-f命令混用 |
-W version or --version | 打印bug报告信息的版本 |
格式说明
格式 | 说明 |
' ' | 引用代码块 |
BEGIN | 初始化代码块 |
// | 匹配代码块,可以是字符串或正则表达式 |
{} | 命令代码块 |
; | 命令间用分号隔开 |
END | 结束代码块 |
常用内置变量
变量 | 说明 |
$0 | 当前整行 |
$[n] | 第n个字段 |
ARGC | 命令行参数的数量 |
ARGV | 命令行参数的数组 |
ENVIRON | 支持使用系统环境变量 |
FILENAME | 正在扫描的文件名 |
FS | 在代码块中设置输入分隔符 |
NF | 字段数 |
NR | 记录数 |
FNR | 浏览的文件的记录数 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
RS | 控制记录分隔符 |
常用表达式
表达式 | 说明 |
length | 获取行长度 |
\t | 制表符 |
\n | 换行符 |
~ | 匹配 |
!~ | 不匹配 |
== | 等于 |
!= | 不等于 |
&& | 逻辑与 |
|| | 逻辑或 |
+ | 匹配时表示1个或1个以上 |
* | 匹配通配符 |
^ | 匹配行的开头 |
$ | 匹配行的结尾 |
/ | 转义符 |
-F'[:;|]' | 在“[]”中定义的多个分隔符 |
举例
文档内容awk-example.txt:
00:2018-06-30;12|23%34,45|56%67,78|89%90,66,123;begin,show some food 01:2018-07-28;12|23%34,45|56%67,78|89%90,66,123;begin,show some food 02:2018-07-29;ab|bc%cd,de|ef%fg,gh|hi%ij,jk,klm;next,buy some vegetables 03:2018-07-30;aa|bb%cc,dd|ee%ff,gg|hh%ii,jj,kkk;other,earn money 04:2018-07-31;11|22%33,44|55%66,77|88%99,66,789;end,go home 05:2018-08-01;1a|2b%3c,4d|5e%6f,7g|8h%9i,0j,0xy;pass,do while night 06:2018-08-02;11|bb%34,de|5e%66,gh|89%ii,jk,789;continue,in the corner 07:2018-08-03;aaa|23i%ccd,4dd|558%6f7,ggy|888%9hi,0jj,xyz;begin,andylouse is a good man 08:2018-08-04;aab|235%cde,4dd|efi%fgg,789|hi8%90i,0jj,abc;again,do well things 09:2018-08-31;aac|123%def,456|opq%678,awk|789%,grep,linux;end,good happiness
文档操作举例:
# 查找第3-6行中以“,”号分隔的第1、3、5列的内容 awk -F , 'FNR==3,FNR==6 {printf "c1: %s\tc3: %s\tc5: %s\n",$1,$3,$5}' awk-example.txt # 查找以“%”号分隔的第1列包含“23”的行 awk -F % '$1 ~ /23/{print $0}' awk-example.txt # 查找以“-”号分隔的第2列等于“07”第3列不包含“28”的行 awk -F - '$2=="07"&&$3!~/28/{printf "%s\n", $0}' awk-example.txt # 遇到“:”和“;”时均换行并另存为新文件 awk -F'[:;]' '{for(i=1;i<=NF;i++){print $i}}' awk-example.txt > awk-new.txt awk -F'[:;]' '{for(i=1;i<=NF;i++){print $i}}' awk-example.txt | tee awk-new.txt # 过滤或替换某列中的字符串 awk 'gsub(/2018-/,"") {print $0}' awk-example.txt awk -F';' 'gsub(/ /,"-",$3) {print $0}' awk-example.txt # 统计字符串“aa”出现的次数 awk '{s+=gsub(/aa/,"&")}END{print s}' awk-example.txt
练习题
# 乘法口诀表 seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}' # 统计某目录下每个用户的文件占用的磁盘空间 ls -l /data | awk 'NR!=1 {fsum[$3]++;sum[$3]+=$5;du="B";u[0]="G";u[1]="M";u[2]="K";uu[0]=1073741824;uu[1]=1048576;uu[2]=1024;}END{for (i in sum) {for (j=0;j<3;j++) {if (sum[i]>=uu[j]) {sum[i]/=uu[j];du=u[j]; printf "用户: %-8s 文件数: %-5d 总容量: %3.2f %-2s\n",i,fsum[i],sum[i],du;break}}}}' # 统计磁盘使用情况 df -m | awk '$1~/^\/dev\//{du+=$3;df+=$4}END{unit="M";if(du>1024 || df>1024){du/=1024;df/=1024;unit="G"} printf "总已用容量:%d%s\n总可用容量:%d%s\n",du,unit,df,unit}' # 抓取目录下所有txt文件内容并写入新的文件 find /opt/ip -name "*.txt" | xargs awk '{print}' >> new.ip awk '{printf "edit bl-%s\nset subnet %s\nnext\n",$1,$1}' new.ip > newest.ip # 一个复杂的处理日志的案例 awk '/.*_2[0-2]:/&&$14>500{print $1" "$9" "$14" "$10}' | awk -F'[ /_]' '{s1[$10]+=$7;s2[$10]+=$6;print "时间:"$4"\t速率:"$7/1024/1024/$6*8"\t域名:"$10}END{for(n in s2){print n" "s1[n]/1024/1024/s2[n]*8}}' # 列转行输出 softinspath=/opt/zabbix/sbin/zabbix_agent echo $softinspath | awk -F[/] '{for (i=2;i<=NF;i++){print $i}}'
掌握-v
# awk -v 一般用于获取环境变量 tst=1 var=2 echo "A test word" | awk -v test="$tst" -v value="$var" '{if(test==value){print $0}}' # 然后修改var的值 var=1 echo "A test word" | awk -v test="$tst" -v value="$var" '{if(test==value){print $0}}'
原创文章禁止转载:技术学堂 » Linux样式扫描与处理工具awk命令及实例分析