Linux三剑客:awk

awk简介

作用:用于linuxUnix下对数据进行处理,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

数组

注意:

  1. awk数组为关联数组,实现key / vaule功能

  2. 可使用任意字符串;字符串要使用双引号括起来

  3. 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

  4. 若要判断数组中是否存在某元素,要使用“key in array”格式

  5. 获得数组长度 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")}'
  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值