shell编程(八):文本处理三剑客之awk

awk的工作模式

语法格式

第一种形式

awk 'BEGIN{}pattern{commands}END{}' file_name
  • BEGIN{}表示文本开始之前,进行{}内的操作
  • END{}表示文本开始以后,进行{}内的操作
  • pattern 表示对那些行进行操作,不写则默认是所有行
  • {commands}对行进行的操作,可以写多个命令
    第二种形式
cat file_name | awk 'BEGIN{}pattern{commands}END{}'

awk的内置变量

n内置变量含义
$0整行内容
1 − 1- 1n当前行的第1-n个字段
NF当前行的字段个数,即多少列
NR当前行的行号,从1开始计数
FNR多个文件处理时,每个文件行号单独计数,都是从0开始
FS输入字段分隔符。不指定默认以空格或tab分割
RS输入行分割符,默认回车换行
OFS输出字段分隔符,默认空格
ORS输出行分隔符。默认回车
FILENAME当前输入的文件名
ARGC命令行参数个数
ARGV命令行参数数组

示例

  • list内容
java:python:scala
hadoop:spark:flume
jake:mike:coco
awk 'BEGIN{FS=":"}{print $1}' list # BEGIN中指定分隔符为:
awk 'BEGIN{FS=":"}{print NR}' list # 显示行号
awk 'BEGIN{FS=":"}{print NF}' list # 显示每行的列数
awk 'BEGIN{FS=":"}{print NF}' list list #行号为连续显示
awk 'BEGIN{FS=":"}{print FNR}' list list1 # 每个文件是单独计算行号
awk 'BEGIN{FS=":"}{print $NF}' list # 输出最后一列

格式化输出printf

格式说明符

格式符含义
%s打印字符串
%d打印十进制数

修饰符

修饰符含义
-左对齐
+右对齐
+显示8进制在前面加0,显示16进制在前面加0x

示例

以字符串格式化打印 /etc/passwd中的第七个字段,并且以":" 作为分隔符

awk 'BEGIN{FS=":"} {printf "%s:",$7}' /etc/passwd

以10进制打印/etc/passwd中第三个字段,以":"作为分隔

awk 'BEGIN{FS=":"} {printf "%10d\n",$3}' /etc/passwd # 右对齐10个字符

浮点数打印

awk 'BEGIN{FS=":"} {printf "%0.2f\n",$3}' /etc/passwd # 浮点数打印 保留两位小数

awk模式匹配的两种方法

第一种模式匹配:RegExp正则表达式匹配

示例
匹配/etc/passwd文件中含有root字符串的所有行

awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd

匹配/etc/passwd文件中以yarn开头的所有行

awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd

第二种模式匹配:关系运算匹配

  • 支持 常用关系运算符 > < >= <= == !=
  • 还支持 ~:匹配正则表达式
  • !~不匹配正则表达式

示例
匹配/etc/passwd中第三个字段小于50的行

awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd

匹配第三个字段包含3个或3个以上的数字信息的所有行

awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd  # /[0-9]{3,}/ 固定写法

布尔运算符匹配
|| 或
&& 与
! 非

匹配/etc/passwd文件中包含hdfs或yarn的所有行信息

awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd

awk中表达式的用法

符号含义
+
*乘法
-
/除法
%取模
^或**乘方
++x先加1
x++后加1

统计/etc/services中空白行的数量

awk '/^$/{sum++} END{print sum}' /etc/services # /^$/ 表示空白行

统计学生分数平均值
学生课程文件如下:

Allen 80 90 96 98
mike 93 98 92 91
zhang 78 76 87 92
awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","name","math","english","chinese","history","avg"} {total=$2+$3+$4+$5;avg=total/4;printf "%-8s%-8d%-8d%-8d%-8d%-0.2f\n",$1,$2,$3,$4,$5,avg}' stu.txt

awk动作中的条件及循环语句

条件语句

if(条件表达式)
	动作1
else if
	动作2
else
	动作3

示例
只打印/etc/passwd/中第3个字段的数值在50-100范围内的行

awk 'BEGIN{FS=":"}{if($3<100 && $3>50) print($0)}' /etc/passwd

将命令写到文件中,并且执行 main.awk

BEGIN{FS=":"}{if($4<100 && $3>50) print($0)}

执行如下语句

awk -f main.awk /etc/passwd

循环语句

while循环
do while
for循环,语法格式和c语言一致。
示例
计算1+2+3+…100的和,使用while、do while、for循环三种方式实现

# for循环
BEGIN{
        for(i=0;i<=100;i++)
        {
                sum+=i
        }
        print sum
}
# while 
BEGIN{
        while(i<=100){
                sum+=i
                i++
        }
        print sum
}
#do while
BEGIN{
        i=0
        do{
           sum+=i
           i++
        }while(i<=100)
        print sum
}

awk中的字符串函数

常用字符串函数

函数名解释函数返回值
length(str)字符串长度整数长度值
index(str1,str2)在str1中查找str2的位置返回位置索引,从1计数
tolower(str)转成小写转化后的字符串
toupper(str)转成大写转化后的字符串
substr(str,m,n)从str的m个字符开始,截取n位截取后的子串
split(str,arr,fs)按照fs切割字符串,结果保存arr切割后子串的个数
match(str,RE)在str中按照RE查找,返回位置返回索引位置
sub(RE,RepStr,str)在str中搜索符合RE的字符串,将其替换为RepStr,只替换一个替换的个数
gsub(RE,RepStr,str)在str中搜索符合RE的字符串,将其替换为RepStr,替换所有替换的个数

示例

统计/etc/passwd中每行,每个字段的长度

BEGIN{
    FS=":"
}
{   i=0
    while(i<=NF)
    {
        if(i==NF){
            printf "%d",$i
        }
        else{
            printf "%d:",$i
        }
        i++
    }
    print ""
}

搜索字符串"I have s dream" 中出现"ea"子串的位置

# 使用index
awk 'BEGIN{str="I have s dream";location=index(str,"ea");print location}'

# 使用match
awk 'BEGIN{str="I have s dream";location=match(str,"ea");print location}' 

字符串大小写转换

awk 'BEGIN{str="I have s dream";print tolower(str)}' 
awk 'BEGIN{str="I have s dream";print toupper(str)}'

字符串分割

awk 'BEGIN{str="I have s dream";split(str,arr," ");for(i in arr) print arr[i]}'

截取子串

awk 'BEGIN{str="I have s dream"; print substr(str,4,5)}'
awk 'BEGIN{str="I have s dream"; print substr(str,4)}' # 第四位开始 

字符串替换

# 将123替换为$ 符号。sub返回的个数,直接修改str
awk 'BEGIN{str="my 123 dream"; sub(/[0-9]+/,"$",str);print str}'

awk选项总结

选项解释
-v参数传递
-f指定脚本文件
-F指定分隔符
-V查看awk版本号

传递参数

num1=20
var="hello world"
awk -v num2="$num1" -v var1="$var" 'BEGIN{print num2,var1}'

awk中的数组

shell中数组用法

定义

array=("Allen" "Mike" "Jick") # 空格分割

数组操作

# 打印元素
echo ${array[2]}
# 打印数组元素个数
echo ${#array[@]}
# 打印数组元素长度
echo ${#array[3]}
# 给元素复制
array[3]="Li"
# 删除元素
unset array[0] # 被删掉后 下标不变
# 分片访问
echo ${array[@]:1:3}
# 元素内容替换
${array[@]/e/E} # 只替换第一个e
${array[@]//e/E} # 替换所有的e

数组遍历

for a in ${array[@]}
do
    echo $a
done

awk中的数组

在awk中,使用数组时,不仅可以使用1,2,3…作为数组下标,还可以使用字符串作为下标
使用数字作为下标

str="Allen Jerry Mike"
split(str,array)
for(i=1;i<=length(array);i++)
	print array[i]

使用字符串作为下标

array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
	print array[a]

awk数组示例

统计tcp链接状态个数

netstat -an | grep tcp | awk '{a[$6]++}END{for(i in a) print i,a[i]}'

计算横向数据总合,计算纵向数据总和

  • 数据
    allen 80 90 87 91
    mike 99 100 100 80
    kobe 99 98 99 100
  • 脚本
BEGIN{
    printf "%-10s%-10s%-10s%-10s%-10s\n","name","yuwen","math","english","total"
}
{
    total=$2+$3+$4
    yuwen_sum+=$2 # 列之间的数累加
    math_sum+=$3
    enlish_sum+=$4
    printf "%-10s%-10s%-10s%-10s%-10s\n",$1,$2,$3,$4,total
}
END{
    printf "%-10s%-10s%-10s%-10s%-10s\n","",yuwen_sum,math_sum,enlish_sum,""
}

awk中getline用法

getline可以实现同时读取两个文件进行操作
示例

  • file1
A 1
B 2
C 3
  • file2
A
C
  • 脚本
BEGIN{
    while(getline<"file1"){a[$1]=$2}  # 将file1中加载到数组中
}
{
    if($1 in a) print $0  # 如果file2中的$1在数组a中 则打印
}
END{
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值