awk简介
作用:用于linux或Unix下对数据进行处理,awk命令支持自定义变量,算数运行,字符串处理,循坏条件判断,数组以及函数等内置功能。
与grep、sed的区别:grep、sed命令对数据逐行处理,awk对数据指定分割字符按列处理。
语法:
awk 选项 '脚本' 文件 选项: -F 分隔符 如 -F: -F[:.-] 默认为空格 -v 变量 如:-v a=10 -f 脚本文件 模式:{处理动作} 正则匹配模式(默认) 匹配成功后执行处理动作 BEGIN模式 处理数据之前的前置操作 END模式 处理数据之后的后置操作
print命令
打印指定列($0代表整行) awk -F: '{print $0}' /etc/passwd $1~n 代表第n列 awk -F: '{print $1$3}' /etc/passwd ,打印默认是空格 awk -F: '{print $1,$3}' /etc/passwd 可以设置打印格式 awk -F: '{print $1"---"$3}' /etc/passwd 支持\t制表位、\n换行 awk -F: '{print $1"\t"$3}' /etc/passwd 案例:获得磁盘利用率,截取文件系统和已用两列,去掉% df | awk '{print $1,$5}' | tr -d % df | awk '{print $1,$5}' | awk -F% '{print $1}'
printf命令
awk '{printf "格式字符串",$n,$m}' 格式字符串 = 格式符 + 修饰符
格式符:
格式符 | 作用 |
---|---|
%c | 显示字符的ASCII码 |
%d %i | 显示十进制整数 |
%e %E | 以科学计数法显示 |
%f | 显示浮点数,即:小数 |
%s | 以字符串显示 |
%u | 显示无符号的整数 |
%% | 显示百分号% |
修饰符:
m.n m控制显示的宽度(默认右对齐); n对于小数表示小数点后精度, 如:%3.1f; 对于整数表示整数位数,不足则前面补0,如:%.3d - 左对齐宽度, 如:%-15s + 显示数值的正负符号 如:%+d
案例:
1.格式化输出用户名和uid awk -F: '{printf "username:%-20s userid:%.3d\n",$1,$3}' /etc/passwd 2.获得磁盘利用率,格式为 文件名:xxx 利用率:xxx df | sed -n '2,$p'| awk '{printf "用户名:%-30s利用率:%d\n",$1,$5}'
变量:
内置变量
内置变量 | 作用 |
---|---|
FS | 设置的分隔符 |
OFS | 输出时的分隔符,默认为空格 |
RS | 定义输入记录的分隔符,默认为换行符 |
ORS | 定义输出记录的分隔符,默认为换行符 |
NF | 按照FS分隔符分割了多少个字段 |
NR | 对每一条记录从1开始进行编号 |
FILENAME | 显示当前记录所在文件名 |
ARGC | 命令行参数的个数,在awk命令参数是指:awk命令本身和文件个数 |
ARGV[n] | ARGV数组存放了命令行各个参数,比如:取第一个参数 ARGV[0],取第二个参数 ARGV[1] |
变量使用案例:
FS变量 awk -F: '{print $1FS$3}' /etc/passwd awk -v FS=":" '{print $1FS$3}' /etc/passwd ################################################################### OFS变量 awk -v FS=":" -v OFS="---" '{print $1,$3}' /etc/passwd user1---1001 user2---1002 test1---1003 ################################################################### RS变量 test.txt aaa;bbb;ccc ddd;eee;fff awk -v RS=";" '{print $0}' test.txt aaa bbb ccc ################################################################### ORS变量 awk -v RS=";" -v ORS="..." '{print $0}' test.txt aaa...bbb...ccc ddd...eee...fff ggg...mmm...nnn... ################################################################### NF变量 打印列数 awk -v FS=":" '{print $1"列数:"NF}' /etc/passwd 打印最后一列 awk -v FS=":" '{print $1"最后列:"$NF}' /etc/passwd ################################################################### NR变量 awk -F: '{print NR,$1}' /etc/passwd awk -F: 'NR>=5&&NR<=10{print NR,$1}' /etc/passwd ################################################################### FILENAME变量 awk -F: '{print $1,FILENAME}' /etc/passwd ################################################################### ARGC变量 awk -F: '{printf "参数数量:%d,参数1:%s,参数2:%s,参数3:%s\n",ARGC,ARGV[0],ARGV[1],ARGV[$(ARGC-1)]}' /etc/passwd test.txt ################################################################### 案例练习: 1.打印passwd倒数第二列 awk -v FS=":" '{print $1"倒数第二列:"$(NF-1)}' /etc/passwd 2.打印passwd第10行 awk -F: 'NR==10{print NR,$1}' /etc/passwd sed -n '10p' /etc/passwd cat /etc/passwd | head -10 | tail -1 cat -n /etc/passwd | tr -d ' ' | grep '^10'
自定义变量
定义变量并输出
awk -v a=10 'BEGIN{print a}' awk 'BEGIN{a=10;print a}'
变量结合文件处理
awk -F: '{title="用户";print $1,title}' /etc/passwd awk -v age=20 -F: '{print $1,age}' /etc/passwd awk -v age=20 -v title="用户" -F: '{print $1title,age"岁"}' /etc/passwd awk -F: '{age=20;title="用户";print $1title,age"岁"}' /etc/passwd
运算符
逻辑运算
运算符 | 描述 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 取反操作 |
三目运算
条件?操作1:操作2
awk模式
模式PATTERN:根据条件,过滤匹配的行,再做处理
空模式
空模式:不指定匹配正则信息,打印所有行
awk -F: '{print $1}' /etc/passwd
正则匹配模式
正则匹配模式:根据正则表达式匹配数据行,匹配到数据行进行处理,未能匹配到数据行不做任何处理
awk '/^UUID/' /etc/fstab awk '$0 ~ /^UUID/' /etc/fstab awk '! /^UUID/' /etc/fstab awk '$0 !~ /^UUID/' /etc/fstab
表达式模式
表达式模式:只有表达式结果为真,则处理对应数据行,如果表达式结果为假,则不对数据行做任何处理
-
表达式为真:非0,非空字符串
-
表达式为假:数字0,或者是空字符串
seq 10 | awk '0' seq 10 | awk '1' seq 10 | awk '"aaa"' seq 10 | awk '""'案例: awk -F: '$3>=1000{print $1,$3}' /etc/passwd awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
行模式
awk不支持直接用行号,但可以使用变量NR间接指定行号进行判断处理
seq 10 | awk 'NR>=3 && NR<=6' awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
awk也支持sed命令的正则范围匹配,匹配一行信息到另一行信息进行处理,比如:匹配以bin开头的行到以sshd开头的行
sed -n '/^bin/,/^sshd/p' /etc/passwd awk '/^bin/,/^sshd/' /etc/passwd awk -F: '/^bin/,/^sshd/{print $1,$3}' /etc/passwd
BEGIN / END 模式
BEGIN模式:仅在开始处理文件中的文本之前执行一次
END模式:仅在文本处理完成之后执行一次
awk -F: 'BEGIN{print "用户","UUID","家目录"};{print $1,$3,$(NF-1)}' /etc/passwd|column -t awk -F: 'BEGIN{print "用户","UUID","家目录"};{print $1,$3,$(NF-1)};END{print "数据处理完毕!"}'/etc/passwd|column -t案例: 统计/etc/service文件中的空白行 [root@centos7 ~ ]# egrep "^$" /etc/services|wc -l 17 [root@centos7 ~ ]# awk '/^$/{i=i+1};END{print i}' /etc/services 17 统计/etc/services文件中有井号开头的行 [root@centos7 ~ ]# egrep "^#" /etc/services|wc -l 102 [root@centos7 ~ ]# awk -v i=0 '/^#/{i=i+1};END{print i}' /etc/services 102 [root@centos7 ~ ]# awk '/^#/{i++};END{print i}' /etc/services 102 统计系统中有多少个虚拟用户和普通用户 [root@centos7 ~ ]# awk -F: -v n=0 -v m=0 'BEGIN{printf "%-20s%-s\n","login_user","nologin_user"};/bash$/{n++};!/bash$/{m++};END{printf "%-20s%s\n",n,m}' /etc/passwd login_user nologin_user 2 21
awk流程控制
if-else语句
有多个判断条件,有条件成立就执行结束,不成立再判断下一个条件
语法:
if(表达式) {...} if(表达式) {...} else {...} if(表达式) {语句1} else if(表达式) {语句2} else {语句3} 案例: 判断奇偶数 awk 'BEGIN{ i = 6; if(i % 2 ==0) {print i"是偶数"} else {print i"是奇数"}}' 判断用户类型 awk -F[:/] '{ if($NF=="bash") {print $1"是普通用户"} else if($NF=="nologin") {print $1"是虚拟用户"} else {print $1"是其他用户"}}' /etc/passwd 判断磁盘分区情况:利用率30以下输出该分区空闲,70以下较满,超过70严重不足 df | sed -n '2,$p' | tr -d % | awk '{ if($5 <= 30) {print $1"比较空闲"} else if($5 <= 70) {print $1"比较满"} else {print $1"空间不足"} }'
switch语句
类似多重if语句,switch对单个值判断
语法:
switch (变量){ case 值1: 语法1;break case 值2: 语法2;break ...... default: 语法N } 案例: 配合shell脚本,定义变量n代表权限数字,输出其代表的权限文字 #!/bin/bash for i in $@ do awk -v n=$i 'BEGIN{ switch(n) { case 0:print "-";break; case 1:print "x";break; case 2:print "w";break; case 3:print "wx";break; case 4:print "r";break; case 5:print "rx";break; case 6:print "rw";break; case 7:print "rwx";break; default:print "按错了"} }' done
while循环
语法:
while (条件) {语句块} 案例: 求1~100的和 awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++};print sum}' 过滤/etc/passwd文件中以root开头的行,输出每一列数据的字符长度 awk -F: '/^root/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/passwd
for循环
语法:
语法1: for(变量 in 数组) {语句} 语法2: for(变量;条件;表达式) {语句} 案例: 求1~100的和 awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}' 过滤/etc/passwd文件中以root开头的行,输出每一列数据的字符长度 awk -F: '/^root/{for(i=1;i<=NF;i++){print $i,length($i)}}' /etc/passwd
break和continue
break 停止循环 awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i;if(i==50)break;};print sum}' continue 跳过本次循环 awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i;};print sum}'
next和exit
awk处理文字的过程类似循环,一行行处理
next 跳过awk本次读取的文字,类似continue exit 停止awk读取文字的过程,类似break,跳到END 案例: 1~10打印,跳过偶数 seq 10 | awk '{if($0%2==0)next;print $0}' 1~10打印,到5中断 seq 10 | awk '{if($0==5)exit;print $0};END{print "Game Over"}' 读取passwd遇到虚拟用户跳过 awk -F[:/] '{if($NF=="nologin")next;print $1,$NF}' /etc/passwd 打印passwd的用户和uid,到uid为1000的停止 awk -F[:/] '{if($3==1000)exit;print $1,$3}' /etc/passwd
数组
注意:
-
awk数组为关联数组,实现key / vaule功能
-
可使用任意字符串;字符串要使用双引号括起来
-
如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
-
若要判断数组中是否存在某元素,要使用“key in array”格式
-
获得数组长度 length(array)
awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"],weekdays["tue"],weekdays["wed"]}' awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print "mon" in weekdays,"wed" in weekdays}' awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'
案例: 把test.txt中所有单词和出现次数打印出来 aaaa aaaa bbb bbb cccc arr[aaaa] 1 arr[aaaa] 2 arr[bbb] 1 arr[bbb] 2 arr[cccc] 1 awk '{arr[$0]++};END{for(i in arr)print i,arr[i]}' test.txt 使用awk去重 awk '!arr[$0]++' test.txt
函数
内置函数
rand(): 返回0和1之间一个随机数 srand(): 配合rand() 函数,生成随机数的种子 int(): 返回整数部分 20~30的随机数 awk 'BEGIN{srand();print 20+ int(rand() * 11)}' length([s]): 返回指定字符串的字符长度或数组的长度 sub(正则表达式,替换内容,$n): 替换指定内容 gsub(正则表达式,替换内容,$n): 全部替换指定内容 替换第1列中的第一个root awk 'sub(/root/,"superadmin",$1)' /etc/passwd 替换整行中的第一个root awk 'sub(/root/,"superadmin",$0)' /etc/passwd 替换整行中所有root awk 'gsub(/root/,"superadmin",$0)' /etc/passwd split($列数, 数组 , 分割符): 分割字符串保存到数组 awk '/^root/{split($0,arr,":");for(i in arr)print i,arr[i]}' /etc/passwd system("shell命令") 调用shell命令 awk 'BEGIN{system("ifconfig")}'