Linux样式扫描与处理工具awk命令及实例分析

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命令及实例分析

精彩评论

8+1=

感谢您的支持与鼓励

支付宝扫一扫打赏

微信扫一扫打赏