Shell(awk)

Posted by YaPi on June 6, 2022

awk

  • awk是一个文本处理工具,通常用于处理数据并生成结果报告
  • 三个创始人名称首字母
  • awk ‘BEGIN{}pattern{command}END’ file_name
  • standard output awk ‘BEGIN{}pattern{command}END’
  • BEGIN{}: 正式处理数据之前执行
  • END{}: 处理匹配之后执行

参数:

  • -v 参数传递
    • awk -v var1=”$num1” -v var2=”$num2” ‘BEGIN{print var1,var2}’
  • -f 指定脚本文件
    • awk -f test.txt /etc/passwd
  • -F 指定分割符
  • -V 查看awk的版本

    内置变量

  • FILENAME
  • ARGC
  • ARGV
# awk 'BEGIN{}pattern{command}END' file_name
# 输出每一行的数据,$0 代表一行数据,默认以空格或tab分割
awk '{print $1}' sed.txt
# 以冒号分割数据,取第二个元素,$0代表整行
awk 'BEGIN{FS=":"}{print $1}' passwd

# NF 表示每一行的元素个数
awk '{print NF}' sed.txt

# NR 表示行号,一起计数
awk '{print NR}' sed.txt test.txt

# FNR 表示行号,单独计数
awk '{print FNR}' sed.txt test.txt

# 指定列分隔符,java|python|go, 以|分割
awk 'BEGIN{FS="|"}{print $2}' test.txt

# 同时指定行分隔符,不指定默认以\n分割
awk 'BEGIN{FS="|";RS="---"}{print $2}' test.txt

# ORS="&" 指定输出换行符为&
awk 'BEGIN{FS="|";RS="---";ORS="&";OFS=":"}{print $1,$3}' test.txt

# 输出文件名
awk '{print FILENAME}' test.txt

# 输出参数个数
awk '{print ARGC}' test.txt # 2

# 命令行数组
awk '{print ARGV}' test.txt

printf

符号 意义
%s 打印字符串
%d 打印10进制数
%f 打印浮点数
%x 打印16进制数
%o 打印8进制数
%e 打印数字的科学计数法格式
%c 打印单个字符ASSCII码
- 左对齐
+ 右对齐
# 显示8进制前面加0,显示16进制前面加0x
awk 'BEGIN{FS=":"}{printf "%s  %s\n ",$1,$2}' passwd

模式匹配的用法

  • RegExp
  • 关系运算匹配 >、<、>=、<=、!=、==、~匹配正则表达式、!~不匹配正则表达式
# 找到文件中包含root的行,并打印整行信息
awk 'BEGIN{FS=":"}/root/{print $0}' passwd
# 找到文件中以nobo开头的行
awk 'BEGIN={FS=":"}/^nobo/{print $0}' passwd
# 找到文件中以冒号分割第三个参数小于10的行
awk 'BEGIN{FS=":"}$3<10{print $0}' passwd
# 找到文件中以冒号分割,第三个参数是3个数字的行信息
# 匹配正则表达式需要 ~/ / 包含起来,固定写法
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' passwd
# 找到文件中第三个参数小于50或第四个参数大于50
# || 、&& 、!
awk 'BEGIN{FS=":"}$3<50 || $4>50 {print $0}' passwd
# 找到文件中的空白行,输出行数
awk '/^$/{sum++}END{print sum}' /etc/services
# 为每一行添加一个平均分字段,并添加表头
awk 'BEGIN{printf "%-5s%-5s%-5s%-5s%-5s%-5s\n","NAME","YW","MATH","EN","WL","AVG"}{total=$2+$3+$4+$5;AVG=total/4;printf "%-5s%-5d%-5d%-5d%-5d%0.2f\n",$1,$2,$3,$4,$5,AVG}' jc.txt

内置函数

分之循环

if 语句

if () {
    ...
}else if () {
    ...
}else {
    ...
}


while语句

do
{    
    动作
}
while(i<100 )

或

while(i<100){

}

for

for (i=0;i<100;i++){
    动作
}
例1

使用冒号分割/etc/passwd文件,并计算每一个元素的长度

BEGIN{
  FS=":"
}
{
  i=1
  while (i<=NF){
    printf "(%s,%d) ",$i,length($i)
    i++
  }
  print "\n"
}
例2
# 查找ea的位置
awk 'BEGIN{str="I have a dream";location=index(str,"ea");print location}'
# match也可以实现,同时match可以指定正则表达式
awk 'BEGIN{str="I have a dream";location=match(str,"ea");print location}'
# 数组下标从1开始
awk 'BEGIN{str="A B C D E F G";split(str,arr," "); for(a in arr) print arr[a]}'
# 正则匹配
awk 'BEGIN{str="I have a dre123am";location=match(str,/[0-9]/);print location}'
# 从第4个位置开始,提取5位
awk 'BEGIN{str="I have a dre123am";print substr(str,4,5)}'
# 将数字替换为$符号,只替换一次
awk 'BEGIN{str="I have 123 a dre123am";sub(/[0-9]+/,"%",str);print str}'
# 全部替换,返回替换次数
awk 'BEGIN{str="I have 123 a dre123am";count=gsub(/[0-9]+/,"%",str);print str,count}'
awk '{if ($3>=70 && $3<=80) print $0}' jc.txt
例3

文件

2020-09-10	A  insert 1890, sucess 1000, fail 100
2020-09-10	B  insert 2890, sucess 1100, fail 200
2020-09-10	C  insert 3890, sucess 1200, fail 300
2020-09-10	D  insert 4890, sucess 1300, fail 400
2020-09-10	E  insert 5890, sucess 1400, fail 500
2020-09-10	F  insert 6890, sucess 1500, fail 600
2020-09-10	B  insert 2890, sucess 1100, fail 200
2020-09-10	C  insert 3890, sucess 1200, fail 300
2020-09-10	D  insert 4890, sucess 1300, fail 400
2020-09-10	E  insert 5890, sucess 1400, fail 500
  • 统计每个人插入了多少条
  • 统计每个人分别成功,失败多少
BEGIN{
  printf "%-20s%-20s%-20s%-20s\n","NAME","TOTAL_RECORD","TOTAL_SUCCESS","TOTAL_FAILED"
}
{
  USER[$2]+=$4
  SUCCESS[$2]+=$6
  FAILED[$2]+=$8
}

END{
    for (user in USER){
      all_total+=USER[user]
      all_sucess+=SUCCESS[user]
      all_failed+=FAILED[user]
      
      printf "%-20s%-20d%-20d%-20d\n",user,USER[user],SUCCESS[user],FAILED[user]
    }
    printf "%-20s%-20d%-20d%-20d\n","",all_total,all_sucess,all_failed
}